réorganiser des pages dans FragmentStatePagerAdapter à l'aide de getItemPosition(Object objet)
Je crois que FragmentStatePagerAdapter ne se comporte pas correctement lors de la substitution getItemPosition(Object object)
avec le but de réorganiser les pages.
Ci-dessous est un exemple simple. Dans l'état initial, l'ordre des pages est {A, B, C}. Sur appel de toggleState()
, l'ordre des pages changements à {A, C, B}. En substituant getItemPosition(Object object)
, nous nous assurons que la page en cours en cours de visualisation (A, B, ou C) ne change pas.
public static class TestPagerAdapter extends FragmentStatePagerAdapter {
private boolean mState = true;
public TestPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public int getCount() {
return 3;
}
private void toggleState() {
mState = !mState;
notifyDataSetChanged();
}
private String getLabel(int position) {
switch (position) {
case 0:
return "A";
case 1:
return mState ? "B" : "C";
default:
return mState ? "C" : "B";
}
}
@Override
public int getItemPosition(Object object) {
String label = ((TestFragment) object).getLabel();
if (label.equals("A")) {
return 0;
} else if (label.equals("B")) {
return mState ? 1 : 2;
} else {
return mState ? 2 : 1;
}
}
@Override
public CharSequence getPageTitle(int position) {
return getLabel(position);
}
@Override
public Fragment getItem(int position) {
return TestFragment.newInstance(getLabel(position));
}
}
J'ai rencontré deux comportements qui semblent incorrectes.
-
Si j'ai immédiatement appel
toggleState()
(lors de l'affichage de la page Une, avant de glisser vers toute autre page), l'application se bloque.java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2 at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251) at java.util.ArrayList.set(ArrayList.java:477) at android.support.v4.app.FragmentStatePagerAdapter.destroyItem(FragmentStatePagerAdapter.java:136) at android.support.v4.view.ViewPager.populate(ViewPager.java:867) at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:469) at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:441) at android.support.v4.view.ViewPager.dataSetChanged(ViewPager.java:766) at android.support.v4.view.ViewPager$PagerObserver.onChanged(ViewPager.java:2519) at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37) at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:276) at com.ugglynoodle.test.testfragmentstatepageradapter.MainActivity$TestPagerAdapter.toggleState(MainActivity.java:55) ...
Regardant le source de
FragmentStatePagerAdapter
, ce serait fixé par vérifier d'abord la taille demFragments
(comme dans les lignes 113-115) avant d'appelerset()
en ligne 136. -
Si j'ai d'abord balayez vers la page B, puis
getItem(2)
est appelé, à la page C est créé, etmFragments
a maintenant une taille de 3 (cela permettra d'éviter le crash au-dessus de passe dans un instant). Ensuite, j'ai balayez vers le retour à Une page, et la page C est détruit, comme il devrait l'être (car il est de 2 pages, et je suis en utilisant la valeur par défaut à l'écran à la limite de page 1). Maintenant, j'appelletoggleState()
. La Page B est aujourd'hui détruit. Néanmoins, la page C est PAS recréé! Cela signifie que, lorsque j'ai maintenant faire glisser vers la droite, j'obtiens une page vide.
Tout d'abord, il serait bon de savoir si je suis correct et ce sont en fait des bugs, ou si je fais quelque chose de mal. Si ils sont des bugs, n'importe qui peut proposer une solution (autre que le débogage et la reconstruction de la bibliothèque de prise en charge moi-même)? Sûrement quelqu'un doit avoir remplacé getItemPosition(Object object)
avec succès (à l'exception de la mise à POSITION_NONE
)?
Je suis à l'aide de la révision en cours (10) de la bibliothèque de prise en charge.
Vous devez vous connecter pour publier un commentaire.
Regardant le source de FragmentStatePagerAdapter, j'ai compris exactement ce qui ne va pas. Le FragmentStatePagerAdapter met en cache les fragments et enregistrés dans les états ArrayLists:
mFragments
etmSavedState
. Mais lorsque les fragments sont réorganisées, il n'y a pas de mécanisme pour réorganiser les éléments demFragments
etmSavedState
. Par conséquent, l'adaptateur de fournir le mauvais fragments pour le pager.J'ai déposé un problème pour cela, et ci-joint un fixe de mise en œuvre (NewFragmentStatePagerAdapter.java) à la question. Dans le corrigé, j'ai ajouté un
getItemId()
fonction de FragmentStatePagerAdapter. (Cela reflète la réorganisation mise en œuvre dans FragmentPagerAdapter.) Un tableau de la itemIds par carte de position est stockée à tout moment. Puis, dansnotifyDataSetChanged()
, la carte vérifie si le itemIds tableau a changé. Si c'est le cas,mFragments
etmSavedState
sont réorganisés en conséquence. D'autres modifications peuvent être trouvés dansdestroyItem()
,saveState()
etrestoreState()
.L'utilisation de cette classe,
getItemPosition()
etgetItemId()
doit être mis en œuvre de manière cohérente avecgetItem()
.Pour moi travaillé l'une des réponses de un problème. Réponses #20 #21. Lien vers la solution https://gist.github.com/ypresto/8c13cb88a0973d071a64.
La meilleure solution, qui fonctionne pour la mise à jour de pages et de réorganisation. Seulement dans cette solution de l'Adaptateur n'a pas de jeter IndexOutOfBoundsExeption lors de la destruction de l'élément (dans la méthode destroyItem), qui est connu de bug pour d'autres solutions.
J'ai ré-implémenté la solution existante dans Kotlin tels qu'il vous permet de retourner un
String
au lieu d'unlong
pour l'id de l'élément. Vous pouvez le trouver ici ou ci-dessous:Et la Java pièce:
Bon, j'ai trouvé une solution. Cela résout la question de la réorganisation des viewpager fragments, dans le cas où vous êtes la création/modification de nouveaux onglets de façon dynamique.
L'utilisation de cette classe à la place de FragmentStatePagerAdapter.java
JS:
et de l'utiliser pour annuler la méthode
JS:
Source : https://issuetracker.google.com/issues/36956111