Mam długi czas, ListView
że użytkownik może przewijać przed powrotem do poprzedniego ekranu. Gdy użytkownik otworzy to ListView
ponownie, chcę, aby lista została przewinięta do tego samego miejsca, w którym była poprzednio. Wszelkie pomysły, jak to osiągnąć?
android
android-listview
scroll
scroll-position
Rantravee
źródło
źródło
Odpowiedzi:
Spróbuj tego:
Objaśnienie:
ListView.getFirstVisiblePosition()
zwraca najwyżej widoczny element listy. Ale ten element może być częściowo przewijany poza zasięgiem wzroku, a jeśli chcesz przywrócić dokładną pozycję przewijania listy, musisz uzyskać to przesunięcie.ListView.getChildAt(0)
Zwraca więc pozycjęView
dla górnej listy, a następnieView.getTop() - mList.getPaddingTop()
zwraca jej względne przesunięcie od góryListView
. Następnie, aby przywrócićListView
pozycję przewijania, wywołujemyListView.setSelectionFromTop()
z indeksem pożądanego elementu i przesunięciem, aby ustawić jego górną krawędź od góryListView
.źródło
int index = mList.getFirstVisiblePosition();
i tylko jedną linię, aby przywrócić:mList.setSelectionFromTop(index, 0);
. Świetna odpowiedź (+1)! Szukałem eleganckiego rozwiązania tego problemu.źródło
Przyjąłem rozwiązanie zaproponowane przez @ (Kirk Woll) i działa dla mnie. Widziałem także w kodzie źródłowym Androida dla aplikacji „Kontakty”, że używają podobnej techniki. Chciałbym dodać więcej szczegółów: Na górze mojej klasy pochodnej ListActivity:
Następnie niektóre metody zastępują:
Oczywiście „loadData” to moja funkcja do pobierania danych z bazy danych i umieszczania ich na liście.
W moim urządzeniu Froyo działa to zarówno po zmianie orientacji telefonu, jak i podczas edycji elementu i powrotu do listy.
źródło
mListState = getListView().onSaveInstanceState().
głównie podczas obracania urządzenia.onRestoreInstanceState
nigdy nie nazywa się :(Bardzo prosty sposób:
Metoda setSelection spowoduje zresetowanie listy do dostarczonego elementu. Jeśli nie jest w trybie dotykowym, pozycja zostanie faktycznie wybrana, jeśli w trybie dotykowym pozycja zostanie ustawiona tylko na ekranie.
Bardziej skomplikowane podejście:
źródło
Znalazłem w tym coś interesującego.
Próbowałem setSelection i scrolltoXY, ale to nie działało wcale, lista pozostała w tej samej pozycji, po kilku próbach i błędach otrzymałem następujący kod, który działa
Jeśli zamiast opublikowania Runnable spróbujesz runOnUiThread, to również nie działa (przynajmniej na niektórych urządzeniach)
Jest to bardzo dziwne obejście dla czegoś, co powinno być proste.
źródło
setSelectionFromTop()
nie działa.UWAGA!! W AbsListView występuje błąd, który nie pozwala na prawidłowe działanie funkcji onSaveState (), jeśli ListView.getFirstVisiblePosition () ma wartość 0.
Więc jeśli masz duże obrazy, które zajmują większość ekranu, i przewijasz do drugiego obrazu, ale niewielka część pierwszego pokazuje, pozycja przewijania nie zostanie zapisana ...
z AbsListView.java:1650 (komentarze moje)
Ale w tej sytuacji „góra” w poniższym kodzie będzie liczbą ujemną, co powoduje inne problemy, które uniemożliwiają prawidłowe przywrócenie stanu. Więc kiedy „góra” jest ujemna, zdobądź następne dziecko
źródło
Wystarczy
źródło
W przypadku niektórych osób poszukujących rozwiązania tego problemu źródłem problemu może być ustawienie adaptera widoków list. Po ustawieniu adaptera w widoku listy resetuje on pozycję przewijania. Tylko coś do rozważenia. Przenieśliśmy ustawienie adaptera do mojego onCreateView po tym, jak złapaliśmy odwołanie do widoku listy, co rozwiązało problem. =)
źródło
Publikuję to, ponieważ jestem zaskoczony, że nikt o tym nie wspominał.
Po kliknięciu przycisku Wstecz użytkownik powróci do widoku listy w takim samym stanie, w jakim go opuścił.
Ten kod zastąpi przycisk „w górę”, aby zachowywać się tak samo jak przycisk Wstecz, więc w przypadku widoku listy -> Szczegóły -> Powrót do widoku listy (i żadnych innych opcji) jest to najprostszy kod do utrzymania pozycji przewijania i zawartości w widoku listy.
Uwaga: jeśli możesz przejść do innego działania z działania dotyczącego szczegółów, przycisk w górę spowoduje powrót do tego działania, więc będziesz musiał manipulować historią przycisku, aby to zadziałało.
źródło
Czy po prostu
android:saveEnabled="true"
deklaracja XML ListView nie wystarczy?źródło
NAJLEPSZE ROZWIĄZANIE TO:
MUSISZ WEZWAĆ W POSTIE I W GWINTU!
źródło
Możesz zachować stan przewijania po przeładowaniu, jeśli zapiszesz stan przed ponownym załadowaniem i przywrócisz po nim. W moim przypadku wysłałem asynchroniczne żądanie sieciowe i po zakończeniu przeładowałem listę w wywołaniu zwrotnym. To tutaj przywracam stan. Przykładowy kod to Kotlin.
źródło
Jeśli używasz fragmentów hostowanych w działaniu, możesz zrobić coś takiego:
źródło
Jeśli zapisujesz / przywracasz swoją pozycję przewijania
ListView
, zasadniczo kopiujesz funkcjonalność już zaimplementowaną w systemie Android.ListView
Przywracanie porządku pozycja przewijania po prostu dobrze we własnym zakresie, z wyjątkiem jedno zastrzeżenie: jak @aaronvargas wspomniano tam jest błąd wAbsListView
że nie pozwoli, aby przywrócić wyśmienitą pozycję przewijania dla pierwszego elementu listy. Niemniej najlepszym sposobem na przywrócenie pozycji przewijania jest jej przywrócenie. System Android zrobi to lepiej dla Ciebie. Upewnij się, że spełniłeś następujące warunki:setSaveEnabled(false)
metody i nie ustawiłeśandroid:saveEnabled="false"
atrybutu dla listy w pliku układu xmlExpandableListView
przesłonięcialong getCombinedChildId(long groupId, long childId)
, tak aby zwracała dodatnią liczbę długą (domyślna implementacja w klasieBaseExpandableListAdapter
zwraca liczbę ujemną). Oto przykłady:.
ListView
lubExpandableListView
jest używany w fragmencie, nie odtwarzaj fragmentu podczas odtwarzania aktywności (na przykład po obróceniu ekranu). Uzyskaj fragmentfindFragmentByTag(String tag)
metodą.ListView
maandroid:id
i jest unikalny.Aby uniknąć wyżej wspomnianego zastrzeżenia dotyczącego pierwszego elementu listy, możesz stworzyć adapter w sposób, w jaki zwraca on specjalny widok wysokości zerowego piksela dla
ListView
pozycji 0. Oto prosty przykładowy projekt pokazujeListView
iExpandableListView
przywraca ich dokładne pozycje przewijania, podczas gdy ich pozycje przewijania nie są jawnie zapisywane / przywrócone. Pozycja dokładnego przewijania jest przywracana idealnie nawet w przypadku złożonych scenariuszy z chwilowym przełączeniem na inną aplikację, podwójnym obrotem ekranu i powrotem do aplikacji testowej. Uwaga: jeśli wyraźnie wychodzisz z aplikacji (naciskając przycisk Wstecz), pozycja przewijania nie zostanie zapisana (podobnie jak wszystkie inne Widoki nie zapiszą swojego stanu). https://github.com/voromto/RestoreScrollPosition/releasesźródło
W przypadku działania pochodzącego z ListActivity, które implementuje LoaderManager.LoaderCallbacks za pomocą SimpleCursorAdapter, nie działało przywracanie pozycji w onReset (), ponieważ działanie prawie zawsze było restartowane, a adapter był ładowany ponownie, gdy widok szczegółów był zamknięty. Sztuką było przywrócenie pozycji w onLoadFinished ():
w onListItemClick ():
w onLoadFinished ():
w onBackPressed ():
źródło
Żadne z zaproponowanych tutaj rozwiązań nie działało dla mnie. W moim przypadku mam
ListView
w a,Fragment
które zastępuję wFragmentTransaction
, więc nowaFragment
instancja jest tworzona za każdym razem, gdy fragment jest wyświetlany, co oznacza, żeListView
stanu nie można zapisać jako członkaFragment
.Zamiast tego zapisałem stan w mojej
Application
klasie niestandardowej . Poniższy kod powinien dać ci wyobrażenie o tym, jak to działa:Podstawową ideą jest przechowywanie stanu poza instancją fragmentu. Jeśli nie podoba ci się pomysł posiadania pola statycznego w klasie aplikacji, myślę, że możesz to zrobić, implementując interfejs fragmentu i zapisując stan w swojej aktywności.
Innym rozwiązaniem byłoby przechowywanie go
SharedPreferences
, ale staje się to nieco bardziej skomplikowane i musisz upewnić się, że wyczyściłeś go podczas uruchamiania aplikacji, chyba że chcesz, aby stan był utrzymywany podczas uruchamiania aplikacji.Ponadto, aby uniknąć „pozycji przewijania, która nie została zapisana, gdy widoczny jest pierwszy element”, można wyświetlić atrapę pierwszego elementu o
0px
wysokości. Można to osiągnąć, zastępującgetView()
adapter w następujący sposób:źródło
Moja odpowiedź dotyczy bazy ogniowej, a pozycja 0 jest obejściem problemu
i convertView
pozycja 0 a dodaj pusty element, którego nie używasz
Widziałem tę pracę tymczasowo, nie przeszkadzając użytkownikowi, mam nadzieję, że zadziała dla Ciebie
źródło
użyj tego kodu poniżej:
a przy każdym odświeżeniu danych użyj poniższego kodu:
źródło
Korzystam z FirebaseListAdapter i nie udało mi się uzyskać żadnego z rozwiązań. Skończyło się na tym. Sądzę, że są bardziej eleganckie sposoby, ale jest to kompletne i działające rozwiązanie.
Przed utworzeniem:
Wewnątrz FirebaseListAdapter:
onStart:
onStop:
Ponieważ musiałem również rozwiązać ten problem dla FirebaseRecyclerAdapter , zamieszczam tutaj również rozwiązanie:
Przed utworzeniem:
Wewnątrz FirebaseRecyclerAdapter:
onStart:
onStop:
źródło
Aby wyjaśnić doskonałą odpowiedź Ryana Newsoma i dostosować ją do fragmentów oraz do zwykłego przypadku, w którym chcemy nawigować z „głównego” fragmentu ListView do „szczegółowego” fragmentu, a następnie z powrotem do „głównego”
„Magia” polega na tym, że kiedy wracamy z fragmentu szczegółów do fragmentu ListView, widok nie jest odtwarzany, nie ustawiamy adaptera ListView, więc wszystko pozostaje tak, jak go zostawiliśmy!
źródło