J'ai un MainActivity
qui a trois fragments dans un FragmentPagerAdapter
comme ci-dessous. Comment savoir quand un utilisateur passe du 1er fragment au second ou du deuxième au troisième, soit en glissant, soit en cliquant sur l'onglet? J'ai vu que la méthode getItem()
n'est pas toujours appelée car j'ai déclaré 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;
}
}
onCreate()
de MainActivity 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);
La méthode getItem()
n'est appelée que lors de la création d'une vue. Pour comprendre pourquoi getItem()
n'est pas appelé, il est utile de comprendre le comportement par défaut d'un ViewPager
. Par défaut, lorsque vous êtes sur une page particulière d'un ViewPager
, il crée également les pages qui se trouvent avant et après cette page particulière. Si vous deviez avoir 3 fragments nommés et dans cet ordre [a, b, c], et que vous étiez à la page b, en raison du comportement par défaut des fragments ViewPager a et c seraient déjà créés avec un appel à la fonction getItem(int)
. Parce que les fragments sont déjà créés, vous n'obtiendrez pas un autre appel à getItem()
En plus: ce comportement peut être modifié avec ViewPager.setOffScreenLimit()
Ce que vous voulez réellement faire pour être averti lorsqu'un utilisateur change de page, c'est définir OnPageChangeListener
sur ViewPager
en utilisant ViewPager.addOnPageChangeListener()
pour être averti lorsqu'une page est sélectionnée.
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) {
}
});
Tout d'abord, je suppose que vous avez les champs déclarés suivants
ViewPager pager;
TabLayout tabs;
MainThreeTabAdapter adapter;
Vous devez ensuite créer votre instance d'adaptateur et la définir sur pager. Ici, vous pouvez ajouter un écouteur appelant addOnPageChangeListener
adapter = new MainThreeTabAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
pager.addOnPageChangeListener(/*here is your listener instance*/);
tabs.setupWithViewPager(pager);
Toujours lorsque la page passe à une nouvelle en faisant glisser ou en cliquant sur l'onglet, la méthode onPageSelected(int position)
sera appelée.
Si vous voulez que l'instance réelle du fragment actuel interagisse directement avec lui, vous pouvez créer votre propre FragmentPagerAdapter
qui devrait mettre en cache les fragments créés:
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 cette façon, vous devez
MainThreeTabAdapter
à partir de CachingFragmentPagerAdapter
addOnPageChangeListener
à ViewPager
rechercher et interagir avec un fragment dans la méthode onPageSelected
comme suit:
public void onPageSelected(int position) {
final Fragment fragment = adapter.getRegisteredFragment(position);
if (fragment instanceof NewsFragment) {
//...
} else ...
}
Si, comme je suppose que vous utilisez un TabLayout avec votre ViewPager, vous devez utiliser addOnTabSelectedListener (). Cela gérera à la fois un clic d'onglet explicite ou un balayage.
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());
}
});