J'ai un long temps ListView
que l'utilisateur peut faire défiler avant de revenir à l'écran précédent. Lorsque l'utilisateur l'ouvre à ListView
nouveau, je veux que la liste défile jusqu'au même point qu'elle était auparavant. Des idées sur la façon d'y parvenir?
android
android-listview
scroll
scroll-position
rantravee
la source
la source
Réponses:
Essaye ça:
Explication:
ListView.getFirstVisiblePosition()
renvoie l'élément de liste visible le plus haut. Mais cet élément peut être partiellement défilé hors de vue, et si vous souhaitez restaurer la position de défilement exacte de la liste, vous devez obtenir ce décalage. Renvoie doncListView.getChildAt(0)
leView
pour l'élément de liste supérieur, puisView.getTop() - mList.getPaddingTop()
renvoie son décalage relatif par rapport au haut deListView
. Ensuite, pour restaurer laListView
position de défilement du, nous appelonsListView.setSelectionFromTop()
avec l'index de l'élément que nous voulons et un décalage pour positionner son bord supérieur à partir du haut duListView
.la source
int index = mList.getFirstVisiblePosition();
et une seule ligne à restaurer:mList.setSelectionFromTop(index, 0);
. Bonne réponse cependant (+1)! Je cherchais une solution élégante à ce problème.la source
J'ai adopté la solution proposée par @ (Kirk Woll), et cela fonctionne pour moi. J'ai également vu dans le code source Android pour l'application "Contacts", qu'ils utilisent une technique similaire. Je voudrais ajouter plus de détails: En plus de ma classe dérivée de ListActivity:
Ensuite, certaines méthodes remplacent:
Bien sûr, "loadData" est ma fonction pour récupérer les données de la base de données et les mettre dans la liste.
Sur mon appareil Froyo, cela fonctionne à la fois lorsque vous modifiez l'orientation du téléphone et lorsque vous modifiez un élément et revenez à la liste.
la source
mListState = getListView().onSaveInstanceState().
principalement sur la rotation de l'appareil.onRestoreInstanceState
n'est jamais appelé :(Une manière très simple:
La méthode setSelection réinitialise la liste à l'élément fourni. S'il n'est pas en mode tactile, l'élément sera réellement sélectionné si en mode tactile, l'élément sera uniquement positionné à l'écran.
Une approche plus compliquée:
la source
J'ai trouvé quelque chose d'intéressant à ce sujet.
J'ai essayé setSelection et scrolltoXY mais cela n'a pas fonctionné du tout, la liste est restée dans la même position, après quelques essais et erreurs, j'ai obtenu le code suivant qui fonctionne
Si au lieu de publier Runnable, vous essayez runOnUiThread, cela ne fonctionne pas non plus (au moins sur certains appareils)
Il s'agit d'une solution de contournement très étrange pour quelque chose qui devrait être simple.
la source
setSelectionFromTop()
ça ne marche pas.MISE EN GARDE!! Il y a un bogue dans AbsListView qui ne permet pas à onSaveState () de fonctionner correctement si ListView.getFirstVisiblePosition () vaut 0.
Donc, si vous avez de grandes images qui occupent la majeure partie de l'écran et que vous faites défiler jusqu'à la deuxième image, mais qu'une petite partie de la première s'affiche, la position de défilement ne sera pas enregistrée ...
de AbsListView.java:1650 (commente le mien)
Mais dans cette situation, le «haut» dans le code ci-dessous sera un nombre négatif qui provoque d'autres problèmes qui empêchent la restauration correcte de l'état. Donc, lorsque le «sommet» est négatif, obtenez le prochain enfant
la source
C'est assez
la source
Pour certains à la recherche d'une solution à ce problème, la racine du problème peut être l'endroit où vous définissez votre adaptateur de vues de liste. Une fois que vous avez défini l'adaptateur dans la liste, il réinitialise la position de défilement. Juste quelque chose à considérer. J'ai déplacé la configuration de l'adaptateur dans mon onCreateView après avoir récupéré la référence à la liste, et cela a résolu le problème pour moi. =)
la source
Je poste cela parce que je suis surpris que personne n'en ait parlé.
Une fois que l'utilisateur a cliqué sur le bouton de retour, il revient à la vue de liste dans le même état qu'il en est sorti.
Ce code remplacera le bouton "haut" pour se comporter de la même manière que le bouton précédent, donc dans le cas de Listview -> Détails -> Retour à Listview (et pas d'autres options) c'est le code le plus simple pour maintenir la position de défilement et le contenu dans la liste.
Attention: Si vous pouvez accéder à une autre activité à partir de l'activité de détails, le bouton haut vous ramènera à cette activité, vous devrez donc manipuler l'historique du bouton de retour pour que cela fonctionne.
la source
N'est-ce pas tout simplement
android:saveEnabled="true"
suffisant dans la déclaration XML ListView?la source
LA MEILLEURE SOLUTION EST:
VOUS DEVEZ APPELER EN POSTE ET EN FIL!
la source
Vous pouvez conserver l'état de défilement après un rechargement si vous enregistrez l'état avant de le recharger et le restaurez après. Dans mon cas, j'ai fait une demande de réseau asynchrone et rechargé la liste dans un rappel une fois terminée. C'est là que je rétablis l'état. L'exemple de code est Kotlin.
la source
Si vous utilisez des fragments hébergés sur une activité, vous pouvez faire quelque chose comme ceci:
la source
Si vous enregistrez / restaurez la position de défilement de
ListView
vous - même, vous dupliquez essentiellement les fonctionnalités déjà implémentées dans le cadre Android. LeListView
restaure la position de défilement fin juste bien, sauf une mise en garde: comme l'a mentionné @aaronvargas, il y a un bugAbsListView
qui ne permet pas de restaurer la position de défilement fin pour le premier élément de la liste. Néanmoins, la meilleure façon de restaurer la position du défilement n'est pas de la restaurer. Le framework Android le fera mieux pour vous. Assurez-vous simplement que vous avez rempli les conditions suivantes:setSaveEnabled(false)
méthode et que vous n'avez pas défini d'android:saveEnabled="false"
attribut pour la liste dans le fichier de disposition xmlExpandableListView
overridelong getCombinedChildId(long groupId, long childId)
method afin qu'il renvoie un nombre long positif (l'implémentation par défaut dans la classeBaseExpandableListAdapter
renvoie un nombre négatif). Voici quelques exemples:.
ListView
ouExpandableListView
est utilisé dans un fragment, ne recréez pas le fragment lors de la recréation d'une activité (après la rotation de l'écran par exemple). Obtenez le fragment avec lafindFragmentByTag(String tag)
méthode.ListView
aandroid:id
et il est unique.Pour éviter la mise en garde susmentionnée avec le premier élément de la liste, vous pouvez créer votre adaptateur de la manière dont il renvoie une vue fictive spéciale à zéro pixel pour la
ListView
position 0. Voici un exemple de projet simple qui montreListView
etExpandableListView
restaure leurs positions de défilement fines alors que leurs positions de défilement ne sont pas explicitement enregistrées / restauré. La position de défilement fine est parfaitement restaurée, même pour les scénarios complexes, avec passage temporaire à une autre application, double rotation de l'écran et retour à l'application de test. Veuillez noter que si vous quittez explicitement l'application (en appuyant sur le bouton Retour), la position de défilement ne sera pas enregistrée (ainsi que toutes les autres vues n'enregistreront pas leur état). https://github.com/voromto/RestoreScrollPosition/releasesla source
Pour une activité dérivée de ListActivity qui implémente LoaderManager.LoaderCallbacks à l'aide d'un SimpleCursorAdapter, il n'a pas fonctionné pour restaurer la position dans onReset (), car l'activité a presque toujours été redémarrée et l'adaptateur a été rechargé lorsque la vue des détails a été fermée. L'astuce était de restaurer la position dans onLoadFinished ():
dans onListItemClick ():
dans onLoadFinished ():
dans onBackPressed ():
la source
Aucune des solutions proposées ici ne semblait fonctionner pour moi. Dans mon cas, j'ai un
ListView
dans unFragment
que je remplace dans unFragmentTransaction
, donc une nouvelleFragment
instance est créée chaque fois que le fragment est affiché, ce qui signifie que l'ListView
état ne peut pas être stocké en tant que membre duFragment
.Au lieu de cela, j'ai fini par stocker l'état dans ma
Application
classe personnalisée . Le code ci-dessous devrait vous donner une idée de comment cela fonctionne:L'idée de base est que vous stockez l'état en dehors de l'instance de fragment. Si vous n'aimez pas l'idée d'avoir un champ statique dans votre classe d'application, je suppose que vous pouvez le faire en implémentant une interface de fragment et en stockant l'état dans votre activité.
Une autre solution serait de le stocker
SharedPreferences
, mais cela devient un peu plus compliqué, et vous devez vous assurer de l'effacer au lancement de l'application, sauf si vous souhaitez que l'état soit conservé pendant les lancements d'applications.De plus, pour éviter la "position de défilement non enregistrée lorsque le premier élément est visible", vous pouvez afficher un premier élément factice avec une
0px
hauteur. Cela peut être réalisé en remplaçantgetView()
votre adaptateur, comme ceci:la source
Ma réponse est pour Firebase et la position 0 est une solution de contournement
et convertView
position 0 a ajouter un élément vierge que vous n'utilisez pas
J'ai vu ce travail temporairement sans déranger l'utilisateur, j'espère qu'il fonctionne pour vous
la source
utilisez ce code ci-dessous:
et chaque fois que vous actualisez vos données, utilisez ce code ci-dessous:
la source
J'utilise FirebaseListAdapter et je n'ai pu faire fonctionner aucune des solutions. J'ai fini par faire ça. Je suppose qu'il existe des moyens plus élégants, mais c'est une solution complète et fonctionnelle.
Avant onCreate:
À l'intérieur de FirebaseListAdapter:
onStart:
onStop:
Étant donné que j'ai également dû résoudre ce problème pour FirebaseRecyclerAdapter, je publie ici la solution pour cela également:
Avant onCreate:
À l'intérieur de FirebaseRecyclerAdapter:
onStart:
onStop:
la source
Pour clarifier l'excellente réponse de Ryan Newsom et l'ajuster pour les fragments et pour le cas habituel où nous voulons naviguer d'un fragment ListView "maître" à un fragment "détails" puis revenir au "maître"
La "magie" ici est que lorsque nous revenons du fragment de détails au fragment ListView, la vue n'est pas recréée, nous ne définissons pas l'adaptateur ListView, donc tout reste tel que nous l'avons laissé!
la source