Używam nowego CoordinatorLayout z AppBarLayout i CollapsingToolbarLayout. Poniżej AppBarLayout mam RecyclerView z listą zawartości.
Sprawdziłem, że przewijanie fling działa w RecyclerView, gdy przewijam listę w górę iw dół. Chciałbym jednak również, aby AppBarLayout płynnie przewijał się podczas rozwijania.
Podczas przewijania w górę w celu rozwinięcia CollaspingToolbarLayout przewijanie zatrzymuje się natychmiast po podniesieniu palca z ekranu. Jeśli przewiniesz w górę w szybkim ruchu, czasami CollapsingToolbarLayout również zwija się ponownie. Wydaje się, że to zachowanie z RecyclerView działa znacznie inaczej niż w przypadku korzystania z NestedScrollView.
Próbowałem ustawić różne właściwości przewijania w widoku recyklingu, ale nie byłem w stanie tego rozgryźć.
Oto film przedstawiający niektóre problemy z przewijaniem. https://youtu.be/xMLKoJOsTAM
Oto przykład przedstawiający problem z RecyclerView (CheeseDetailActivity). https://github.com/tylerjroach/cheesesquare
Oto oryginalny przykład wykorzystujący NestedScrollView od Chrisa Banesa. https://github.com/chrisbanes/cheesesquare
Odpowiedzi:
Odpowiedź Kirilla Boyarshinova była prawie poprawna.
Głównym problemem jest to, że RecyclerView czasami podaje nieprawidłowy kierunek rzucania, więc jeśli dodasz następujący kod do jego odpowiedzi, działa on poprawnie:
Mam nadzieję, że to pomoże.
źródło
if (target instanceof SwipeRefreshLayout && velocityY < 0) { target = ((SwipeRefreshLayout) target).getChildAt(0); }
przedif (target instanceof RecyclerView && velocityY < 0) {
Wygląda na to, że
v23
aktualizacja jeszcze tego nie naprawiła.Znalazłem coś w rodzaju hacka, aby to naprawić, rzucając w dół. Sztuczka polega na tym, aby ponownie wykorzystać zdarzenie rzucające, jeśli górny element podrzędny ScrollingView znajduje się blisko początku danych w adapterze.
Użyj go w swoim układzie w ten sposób:
EDYCJA: Ponowne wykorzystanie wydarzeń Rzut jest teraz oparte na
verticalScrollOffset
liczbie przedmiotów, które znajdują się na wierzchuRecyclerView
.EDIT2: Sprawdź cel jako
ScrollingView
instancję interfejsu zamiastRecyclerView
. ObieRecyclerView
iNestedScrollingView
wdrożyć to.źródło
verticalScrollOffset
która jest bardziej ogólna. Teraz rzucane wydarzenie zostanie ponownie wykorzystane porecyclerView
przewinięciu do góry.target instanceof RecyclerView
natarget instanceof NestedScrollView
lub więcej dla ogólnej wielkości liter natarget instanceof ScrollingView
. Zaktualizowałem odpowiedź.Znalazłem poprawkę, stosując OnScrollingListener do pliku recyclinglerView. teraz działa bardzo dobrze. Problem polega na tym, że recykling podał nieprawidłową zużytą wartość, a zachowanie nie wie, kiedy widok recyklingu jest przewijany do góry.
źródło
CoordinatorLayout
iViewPager
konfiguracja, dziękuję bardzo za to najbardziej oczekiwane rozwiązanie. Proszę napisać GIST dla tego samego, aby inni deweloperzy również mogli z niego skorzystać. Udostępniam również to rozwiązanie. Dzięki jeszcze raz.Zostało to naprawione od czasu wsparcia projektu 26.0.0.
źródło
To jest płynna wersja Google Support Design AppBarLayout. Jeśli używasz AppBarLayout, wiesz, że ma problem z flingiem.
Zobacz bibliotekę tutaj .. https://github.com/henrytao-me/smooth-app-bar-layout
źródło
To błąd dotyczący recyklingu. Ma to zostać naprawione w wersji 23.1.0.
spójrz na https://code.google.com/p/android/issues/detail?id=177729
źródło
v26.0.1
!To jest mój układ i zwój. Działa tak, jak powinien.
źródło
Moje dotychczasowe rozwiązanie na podstawie odpowiedzi Mak Sing i Manolo Garcia .
To nie jest do końca idealne. Na razie nie wiem, jak przeliczyć prędkość walidową, aby uniknąć dziwnego efektu: pasek aplikacji może rozszerzać się szybciej niż prędkość przewijania. Ale stan z rozszerzonym paskiem aplikacji i przewijanym widokiem recyklera nie jest dostępny.
źródło
Field viewFlingerField = recyclerView.getClass().getDeclaredField("mViewFlinger"); viewFlingerField.setAccessible(true); Object flinger = viewFlingerField.get(recyclerView); Field scrollerField = flinger.getClass().getDeclaredField("mScroller"); scrollerField.setAccessible(true); ScrollerCompat scroller = (ScrollerCompat) scrollerField.get(flinger); velocity = Math.signum(mVelocity) * Math.abs(scroller.getCurrVelocity());
W moim przypadku pojawił się problem polegający na rzucaniu pliku
RecyclerView
że nie przewijało go płynnie, co powodowało, że utknęło.To dlatego, że z jakiegoś powodu zapomniałem, że włożyłem
RecyclerView
plikNestedScrollView
.To głupi błąd, ale zajęło mi trochę czasu, zanim to rozgryzłem ...
źródło
Dodaję widok wysokości 1 dp wewnątrz AppBarLayout i wtedy działa znacznie lepiej. To jest mój układ.
źródło
Już tutaj kilka dość popularnych rozwiązań, ale po zabawie z nimi wymyśliłem raczej prostsze rozwiązanie, które działało dobrze. Moje rozwiązanie zapewnia również, że
AppBarLayout
jest on rozszerzany tylko wtedy, gdy przewijalna zawartość osiąga szczyt, co stanowi przewagę nad innymi rozwiązaniami tutaj.źródło
Przyjęta odpowiedź nie działała dla mnie, ponieważ miałem
RecyclerView
wewnątrz aSwipeRefreshLayout
iViewPager
. To jest ulepszona wersja, która szukaRecyclerView
w hierarchii i powinna działać dla każdego układu:źródło
Odpowiedź: Naprawiono to w bibliotece wsparcia v26
ale v26 ma jakiś problem z rzucaniem. Czasami AppBar odbija się ponownie, nawet jeśli rzucanie nie jest zbyt trudne.
Jak usunąć efekt odbijania na pasku aplikacji?
Jeśli napotkasz ten sam problem podczas aktualizacji do obsługi wersji 26, oto podsumowanie tej odpowiedzi .
źródło
Julian Os ma rację.
Odpowiedź Manolo Garcia nie działa, jeśli widok recyklingu jest poniżej progu i przewija się. Musisz porównać widok
offset
recyklingu ivelocity to the distance
, a nie pozycję przedmiotu.Stworzyłem wersję java, odwołując się do kodu kotlin Juliana i odejmując odbicie.
źródło
BaseApplication
Znalazłem poprawkę autorstwa Eniz Bilgin https://stackoverflow.com/a/45090239/7639018
Problem został rozwiązany z bibliotekami w tym repozytorium.
( https://developer.android.com/topic/libraries/support-library/setup.html )
źródło
W odniesieniu do narzędzia do śledzenia problemów Google błędów , został on naprawiony w bibliotece wsparcia w wersji 26.0.0-beta2 dla systemu Android
Zaktualizuj bibliotekę obsługi Androida do wersji 26.0.0-beta2.
Jeśli jakikolwiek problem będzie się powtarzał, zgłoś go do narzędzia Google do śledzenia problemów , które ponownie otworzą w celu zbadania.
źródło
Dodanie tutaj kolejnej odpowiedzi, ponieważ powyższe albo nie spełniły całkowicie moich potrzeb, albo nie działały zbyt dobrze. Ten jest częściowo oparty na pomysłach, które tu rozprzestrzeniają.
Więc co to robi?
Scenariusz w dół: jeśli AppBarLayout jest zwinięty, pozwala RecyclerView na samodzielne uruchamianie bez wykonywania jakichkolwiek czynności. W przeciwnym razie zwija AppBarLayout i uniemożliwia RecyclerView wykonanie jego zrzutu. Gdy tylko zostanie zwinięty (do punktu, którego wymaga dana prędkość) i jeśli pozostanie prędkość, RecyclerView zostanie wyrzucony z pierwotną prędkością minus to, co AppBarLayout właśnie zużyło podczas zwijania.
Scenariusz w górę: Jeśli przesunięcie przewijania RecyclerView jest różne od zera, zostanie wyrzucony z oryginalną prędkością. Jak tylko to się zakończy i jeśli nadal pozostanie prędkość (tj. RecyclerView przewinie się do pozycji 0), AppBarLayout zostanie rozszerzony do punktu, w którym pierwotna prędkość pomniejszona o właśnie zużyte wymagania. W przeciwnym razie AppBarLayout zostanie rozszerzony do punktu wymaganego przez pierwotną prędkość.
AFAIK, to jest wcięcie.
Jest w tym dużo refleksji i jest to dość zwyczajowe. Nie znaleziono jeszcze żadnych problemów. Jest również napisany w języku Kotlin, ale zrozumienie tego nie powinno stanowić problemu. Możesz użyć wtyczki IntelliJ Kotlin, aby skompilować go do kodu bajtowego -> i zdekompilować z powrotem do Javy. Aby go użyć, umieść go w pakiecie android.support.v7.widget i ustaw jako zachowanie CoordinatorLayout.LayoutParams w AppBarLayout w kodzie (lub dodaj odpowiedni konstruktor xml lub coś w tym stylu)
źródło
to jest moje rozwiązanie w moim projekcie.
po prostu zatrzymaj mScroller po otrzymaniu Action_Down
xml:
FixAppBarLayoutBehavior.java:
źródło
dla androidx,
Jeśli plik manifestu zawiera wiersz android: hardwareAccelerated = "false", usuń go.
źródło