android - studio - tablayout viewpager
Cómo desplazarse mediante tablayout mediante programación-Android (13)
He creado 30 pestañas desplazables usando tablayout.
Por lo tanto, las tres primeras pestañas están visibles en la pantalla y el resto de ellas son invisibles, las cuales se pueden desplazar con el gesto de deslizar.
El problema es cuando selecciono la última pestaña programáticamente pero no se puede ver (el diseño de la pestaña no se desplaza a la última pestaña).
¿Cómo puedo hacer tablayout para desplazarme a la última pestaña?
¿Está llamando tab.select()
antes de que el TabLayout y sus hijos realmente hayan sido medidos y dibujados? Si es así, su TabLayout no animará la selección con tab.select()
(o la sugerencia de Kayvan N de scrollTo()
). El uso de un controlador probablemente funcionará, pero esa no es una solución ideal.
Siempre que el diseño aún no se haya distribuido, un ViewTreeObserver
le permitirá moverse a la pestaña seleccionada una vez finalizado el proceso de diseño.
private void scrollToTabAfterLayout(final int tabIndex) {
if (getView() != null) {
final ViewTreeObserver observer = mTabLayout.getViewTreeObserver();
if (observer.isAlive()) {
observer.dispatchOnGlobalLayout(); // In case a previous call is waiting when this call is made
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
observer.removeOnGlobalLayoutListener(this);
} else {
//noinspection deprecation
observer.removeGlobalOnLayoutListener(this);
}
mTabLayout.getTabAt(tabIndex).select();
}
});
}
}
}
Por favor comenta si tienes alguna sugerencia.
El siguiente fragmento de código funciona para mí
class TriggerOnceListener(private val v: View, private val block: () -> Unit) : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
block()
v.viewTreeObserver.removeOnPreDrawListener(this)
return true
}
}
fun onCreate() {
val position = ***The tab position you want to scroll to, 29 for your case here***
tabLayout.let { it.viewTreeObserver.addOnPreDrawListener(TriggerOnceListener(it)
{ it.setScrollPosition(position, 0f, true) } ) }
}
Me sumergí en Tab.select (), y encontré que Android usa Tablayout.setScrollPosition () para hacer este desplazamiento. Y en onCreate () los widgets no se han medido, debe posponer la llamada hasta que se complete el diseño.
Encontré esta solución para mí:
TabLayout tabLayout = activity.getTabLayout();
tabLayout.setSmoothScrollingEnabled(true);
tabLayout.setScrollPosition(targetChannelPosition, 0f, true);
Además, si recibe este error: "Solo el hilo original que creó una jerarquía de vistas puede tocar sus vistas", puede usar este código para ejecutar en el hilo de Ui:
// find a way to get the activity containing the tab layout
TabLayout tabLayout = activity.getTabLayout();
activity.runOnUiThread(new Runnable()
{
@Override
public void run()
{
TabLayout.Tab tab = tabLayout.getTabAt(targetChannelPosition);
tab.select();
}
});
Encontré la solución.
Primero encontré el ancho de tablayout y me desplazo desde la posición x al ancho y luego lo llamé el método select () de la última pestaña.
Y funciona bien.
A continuación se muestra el código.
mTabLayout.setScrollX(mTabLayout.getWidth());
mTabLayout.getTabAt(lastTabIndex).select();
Actualizado :
Si lo de arriba no funciona, también puede usar el código de abajo, también funciona bien.
new Handler().postDelayed(
new Runnable() {
@Override public void run() {
mTabLayout.getTabAt(TAB_NUMBER).select();
}
}, 100);
Esta solución funcionó para mí. Aunque mi situación es un poco diferente; en mi caso, estoy usando el TabLayout con un ViewPager y agregando más vistas y llamando a notifyDataSetChange ().
La solución es establecer una devolución de llamada en el observador de TabLayout y desplazarse cuando los hijos se agreguen al TabLayout. Aquí está mi ejemplo:
/**
Keep in mind this is how I set my TabLayout up...
PagerAdapter pagerAdapter = new PagerAdapter(...);
ViewPager pager = (ViewPager)findViewById(...);
pager.setAdapter(pagerAdapter);
TabLayout tabLayout = (TabLayout)findViewById(...);
tabLayout.setupWithViewPager(pager);
*/
public void loadTabs(String[] topics) {
animateTabsOpen(); // Irrelevant to solution
// Removes fragments from ViewPager
pagerAdapter.clear();
// Adds new fragments to ViewPager
for (String t : topics)
pagerAdapter.append(t, new TestFragment());
// Since we need observer callback to still animate tabs when we
// scroll, it is essential to keep track of the state. Declare this
// as a global variable
scrollToFirst = true;
// Alerts ViewPager data has been changed
pagerAdapter.notifyOnDataSetChanged();
// Scroll to the beginning (or any position you need) in TabLayout
// using its observer callbacks
tabs.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
/**
We use onGlobalLayout() callback because anytime a tab
is added or removed the TabLayout triggers this; therefore,
we use it to scroll to the desired position we want. In my
case I wanted to scroll to the beginning position, but this
can easily be modified to scroll to any position.
*/
if (scrollToFirst) {
tabs.getTabAt(0).select();
tabs.scrollTo(0, 0);
scrollToFirst = false;
}
}
});
}
Aquí está mi código para el PagerAdapter si también lo necesita lol:
public class PagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragments;
private List<String> titles;
public PagerAdapter(FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<>();
this.titles = new ArrayList<>();
}
/**
* Adds an adapter item (title and fragment) and
* doesn''t notify that data has changed.
*
* NOTE: Remember to call notifyDataSetChanged()!
* @param title Fragment title
* @param frag Fragment
* @return This
*/
public PagerAdapter append(String title, Fragment frag) {
this.titles.add(title);
this.fragments.add(frag);
return this;
}
/**
* Clears all adapter items and doesn''t notify that data
* has changed.
*
* NOTE: Rememeber to call notifyDataSetChanged()!
* @return This
*/
public PagerAdapter clear() {
this.titles.clear();
this.fragments.clear();
return this;
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
@Override
public int getItemPosition(Object object) {
int position = fragments.indexOf(object);
return (position >= 0) ? position : POSITION_NONE;
}
}
La respuesta anterior no funcionaría porque primero, como lo mencionó agirardello, no debe usar mTabLayout.getWidth()
ya que no devuelve lo que necesitamos (que es la posición del niño al que desea desplazarse) y la solución actualizada no funciona. t siempre funciona debido a un error en TabLayout (reportado here ) pero una solución es simple.
Las pestañas en el tabLayout no son hijos directos del TabLayout, por lo que debemos profundizar un nivel usando
((ViewGroup) mTabLayout.getChildAt(0)).getChildAt(YOUR_DESIRED_TAB_INDEX).getRight()
el único hijo de tabLayout es un TabLayout.SlidingTabStrip
que también es un ViewGroup
y getRight()
nos dará la posición más correcta de nuestra vista de pestañas deseada. Así, desplazarnos a esa posición nos dará lo que deseamos. Aquí hay un código completo:
int right = ((ViewGroup) mTabLayout.getChildAt(0)).getChildAt(4).getRight();
mTabLayout.scrollTo(right,0);
mTabLayout.getTabAt(4).select();
NOTA: Asegúrese de llamar a estos métodos después de que el diseño se haya ahogado (como onResume y no onCreate)
Espero que esto ayude.
Me pregunto si esta respuesta será relevante ya que llegará muy tarde. De hecho lo logré en C # usando Xamarin.
tabs.GetChildAt(0).Selected = true;
viewPager.SetCurrentItem(0, true);
Para seleccionar la última pestaña, use tabLayout.getTabAt (X) .select (); donde X es el índice de la última pestaña
Si su TabLayout
se usa junto con un ViewPager
, que es común, simplemente agregue lo siguiente en el método onCreate()
en su Actividad:
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout);
El hecho de que algunas de las pestañas no se muestren indica que el atributo tabMode está establecido en app:tabMode="scrollable"
.
escriba este método en su tablayout personalizado (su propio diseño que extiende el tablayout). Por lo tanto, en el futuro, puede utilizar este método siempre que necesite un sistema de duplicación de código.
public void selectTabAt(int tabIndex) {
if (tabIndex >= 0 && tabIndex < getTabCount() && getSelectedTabPosition() != tabIndex) {
final Tab currentTab = getTabAt(tabIndex);
if (currentTab != null) {
this.post(new Runnable() {
@Override
public void run() {
currentTab.select();
}
});
}
}
}
Si no quieres que uses CustomLayout. solo puedes hacer esto
final Tab currentTab = mTabLayout.getTabAt(tabIndex);
if(currentTab != null){
mTabLayout.post(new Runnable() {
@Override
public void run() {
currentTab.select();
}
});
}
viewpager.setItem(position)
también debe establecer la posición de la pestaña
new Handler().postDelayed(
new Runnable() {
@Override public void run() {
mTabLayout.getTabAt(TAB_NUMBER).select();
}
}, 100);
tab = tabLayout.getSelectedTabPosition();
tab++;
TabLayout.Tab tabs = tabLayout.getTabAt(tab);
if (tabs != null) {
tabs.select();
}
else {
tabLayout.getTabAt(0).select();
}
Si desea la siguiente pestaña en el evento de clic, use este código para que funcione perfectamente.