practice - tablayout android example
FragmentPagerAdapter: ¿cómo detectar un deslizamiento o un clic de pestaña cuando el usuario accede a una nueva pestaña? (4)
El método getItem()
solo se llama cuando se crea una vista. Para comprender por qué no se llama a getItem()
, ayuda a comprender el comportamiento predeterminado de un ViewPager
. De forma predeterminada, cuando está en una página particular de un ViewPager
, también crea las páginas que están antes y después de esta página en particular. Si tuviera 3 fragmentos nombrados y en este orden [a, b, c], y estuviera en la página b, debido al comportamiento predeterminado de los fragmentos de ViewPager a y c ya se crearía con una llamada a getItem(int)
. Debido a que los fragmentos ya están creados, no recibirá otra llamada a getItem()
Aparte: este comportamiento se puede modificar con ViewPager.setOffScreenLimit()
Lo que realmente desea hacer para recibir una notificación cuando un usuario cambia de página es configurar un OnPageChangeListener
para el ViewPager
usando ViewPager.addOnPageChangeListener()
para que se le notifique cuando se selecciona una página.
Tengo una MainActivity
que tiene tres fragmentos en un FragmentPagerAdapter
como se muestra a continuación. ¿Cómo puedo saber cuándo un usuario pasa del primer fragmento al segundo o del segundo al tercero, con solo deslizar o haciendo clic en la pestaña? Vi que el método getItem()
no se llama siempre, ya que he declarado mViewPager.setOffscreenPageLimit(2)
;
public class MainThreeTabAdapter extends FragmentPagerAdapter {
private final String[] CONTENT = new String[]{"News", "Rewards", "Me"};
public MainThreeTabAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
if (position == 0) {
return NewsFragment.newInstance();
} else if (position == 1) {
return RewardsFragment.newInstance();
} else if (position == 2) {
return MeFragment.newInstance(true, App.getAccountData().getId());
} else {
return null;
}
}
@Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
@Override
public int getCount() {
return CONTENT.length;
}
}
En el onCreate de onCreate()
mainThreeTabAdapter = new MainThreeTabAdapter(getFragmentManager());
// Set up the ViewPager with the sections adapter.
// this ensures that 2 tabs on each side of current are kept in memory, which is all we need for our case. Default = 1
// this is all taken from the Quickreturn facebook sample app
mViewPager.setOffscreenPageLimit(2);
mViewPager.setAdapter(mainThreeTabAdapter);
En primer lugar supongo que tienes los siguientes campos declarados.
ViewPager pager;
TabLayout tabs;
MainThreeTabAdapter adapter;
A continuación, debe crear su instancia de adaptador y establecerla en paginador. Aquí puede agregar oyente llamando a addOnPageChangeListener
adapter = new MainThreeTabAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
pager.addOnPageChangeListener(/*here is your listener instance*/);
tabs.setupWithViewPager(pager);
Siempre que la página cambie a una nueva al deslizar o hacer clic en la pestaña, se onPageSelected(int position)
al método onPageSelected(int position)
.
Si desea obtener una instancia real del fragmento actual para interactuar con él directamente, puede crear su propio FragmentPagerAdapter
que debería almacenar en caché los fragmentos creados:
public abstract class CachingFragmentPagerAdapter extends FragmentPagerAdapter {
private final SparseArray<Fragment> registeredFragments = new SparseArray<>();
public CachingFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
public SparseArray<Fragment> getRegisteredFragments() {
return registeredFragments;
}
}
De esta manera tienes que
- extienda su
MainThreeTabAdapter
desdeCachingFragmentPagerAdapter
- agregar
addOnPageChangeListener
aViewPager
encuentre e interactúe con el fragmento en el método
onPageSelected
como sigue:public void onPageSelected(int position) { final Fragment fragment = adapter.getRegisteredFragment(position); if (fragment instanceof NewsFragment) { //... } else ... }
Si asumo que está usando un TabLayout con su ViewPager, debería usar addOnTabSelectedListener (). Esto manejará tanto un clic de tabulación explícito como un deslizamiento.
mTabLayout.setupWithViewPager(mViewPager);
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
Logger.d(TAG, "tabSelected: " + tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
Logger.d(TAG, "tabUnselected: " + tab.getPosition());
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
Logger.d(TAG, "tabReselected: " + tab.getPosition());
}
});
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOffscreenPageLimit(4);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
_position = position;
switch (position) {
case 0:
_header.setButtonVisible(1, View.GONE);
break;
case 1:
_header.setButtonVisible(1, View.GONE);
break;
case 2:
_header.setButtonVisible(1, View.VISIBLE);
break;
case 3:
_header.setButtonVisible(1, View.VISIBLE);
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});