Czy jest możliwe uzyskanie aktualnej pozycji przewijania lub bieżącej strony <ScrollView>
komponentu w React Native?
Więc coś takiego:
<ScrollView
horizontal={true}
pagingEnabled={true}
onScrollAnimationEnd={() => {
// get this scrollview's current page or x/y scroll position
}}>
this.state.data.map(function(e, i) {
<ImageCt key={i}></ImageCt>
})
</ScrollView>
ios
reactjs
react-native
Śpiewał
źródło
źródło
Odpowiedzi:
Próbować.
I wtedy:
źródło
event.nativeEvent.contentOffset.x
jeśli masz poziomy ScrollView;) Dzięki!scrollEventThrottle
16 lub niższej (aby uzyskać zdarzenie dla każdej klatki), nie ma gwarancji, że zgłosi to przesunięcie w ostatniej klatce - co oznacza, że aby mieć pewność, że masz właściwe przesunięcie po zakończeniu przewijania, musisz ustawićscrollEventThrottle={16}
i zaakceptować wpływ tego na wydajność.event.nativeEvent.contentOffset.y
?Uwaga: poniższe informacje są przede wszystkim wynikiem moich własnych eksperymentów w React Native 0.50. W
ScrollView
dokumentacji brakuje obecnie wielu informacji przedstawionych poniżej; na przykładonScrollEndDrag
jest całkowicie nieudokumentowany. Ponieważ wszystko tutaj opiera się na nieudokumentowanym zachowaniu, niestety nie mogę obiecać, że te informacje pozostaną poprawne za rok, a nawet za miesiąc.Ponadto wszystko poniżej zakłada czysto pionowy widok scroll, którego offset Y nas interesuje; tłumaczenie na przesunięcia x , jeśli zajdzie taka potrzeba, jest miejmy nadzieję łatwym ćwiczeniem dla czytelnika.
Różne programy obsługi zdarzeń w
ScrollView
ujęciuevent
i pozwalają uzyskać bieżącą pozycję przewijania za pośrednictwemevent.nativeEvent.contentOffset.y
. Niektóre z tych programów obsługi mają nieco inne zachowanie między systemami Android i iOS, jak opisano szczegółowo poniżej.onScroll
W systemie Android
Odpala każdą klatkę, gdy użytkownik przewija, na każdej klatce, gdy widok przewijania przesuwa się po jej zwolnieniu, na ostatniej klatce, gdy widok przewijania zatrzymuje się, a także zawsze, gdy przesunięcie widoku przewijania zmienia się w wyniku jego ramki zmieniające się (np. z powodu rotacji z poziomego na pionowy).
Na iOS
Pożary, gdy użytkownik przeciąga lub gdy przesuwa się widok przewijania, z pewną częstotliwością określoną przez
scrollEventThrottle
i co najwyżej raz na klatkę, kiedyscrollEventThrottle={16}
. Jeśli użytkownik zwolni widok przewijania, gdy ma on wystarczający pęd do szybowania, przewodnikonScroll
również wystrzeli, gdy dojdzie do spoczynku po szybowaniu. Jednakże, jeśli użytkownik przeciągnie, a następnie zwolni widok przewijania, gdy jest on nieruchomy, nieonScroll
ma gwarancji, że uruchomi się w końcowej pozycji, chyba że zostało ustawione tak, że uruchamia każdą klatkę przewijania.scrollEventThrottle
onScroll
Ustawienie wiąże się z kosztem wydajności,
scrollEventThrottle={16}
który można zmniejszyć, ustawiając go na większą liczbę. Oznacza to jednak, żeonScroll
nie będzie odpalać każdej klatki.onMomentumScrollEnd
Uruchamia się, gdy widok przewijania zatrzymuje się po szybowaniu. W ogóle nie uruchamia się, jeśli użytkownik zwolni widok przewijania, gdy jest nieruchomy, tak że nie ślizga się.
onScrollEndDrag
Uruchamia się, gdy użytkownik przestaje przeciągać widok przewijania - niezależnie od tego, czy widok przewijania jest nieruchomy, czy zaczyna się ślizgać.
Biorąc pod uwagę te różnice w zachowaniu, najlepszy sposób śledzenia przesunięcia zależy od konkretnych okoliczności. W najbardziej skomplikowanym przypadku (musisz obsługiwać Androida i iOS, w tym obsługiwać zmiany w
ScrollView
ramce ze względu na obrót, a nie chcesz akceptować spadku wydajności na Androidzie z ustawieniascrollEventThrottle
na 16) i musisz obsługiwać zmienia się również zawartość w widoku przewijania, wtedy jest to właściwy cholerny bałagan.Najprostszy przypadek jest taki, jeśli potrzebujesz tylko obsługi Androida; po prostu użyj
onScroll
:Aby dodatkowo obsługiwać iOS, jeśli z przyjemnością uruchamiasz program
onScroll
obsługi każdą klatkę i akceptujesz wpływ na wydajność, a jeśli nie musisz obsługiwać zmian ramek, jest to tylko trochę bardziej skomplikowane:Aby zmniejszyć narzut wydajności na iOS, jednocześnie gwarantując, że rejestrujemy dowolną pozycję, na której ustala się widok przewijania, możemy zwiększyć
scrollEventThrottle
i dodatkowo zapewnićonScrollEndDrag
obsługę:Ale jeśli chcemy obsłużyć zmiany ramek (np. Ponieważ pozwalamy na obracanie urządzenia, zmieniając dostępną wysokość ramki widoku scroll) i / lub zmiany treści, to musimy dodatkowo zaimplementować oba
onContentSizeChange
ionLayout
śledzić wysokość obu ramka widoku przewijania i jej zawartość, a tym samym nieustannie obliczaj maksymalne możliwe przesunięcie i wnioskuj, kiedy przesunięcie zostało automatycznie zmniejszone z powodu zmiany rozmiaru ramki lub zawartości:Tak, to dość przerażające. Nie jestem też w 100% pewien, że zawsze będzie działać dobrze w przypadkach, gdy jednocześnie zmieniasz rozmiar ramki i zawartość widoku przewijania. Ale to najlepsze, co mogę wymyślić, i dopóki ta funkcja nie zostanie dodana w ramach samej struktury , myślę, że jest to najlepsze, co każdy może zrobić.
źródło
Odpowiedź Brada Oylera jest prawidłowa. Ale otrzymasz tylko jedno wydarzenie. Jeśli chcesz otrzymywać ciągłe aktualizacje pozycji przewijania, ustaw
scrollEventThrottle
rekwizyt w następujący sposób:I program obsługi zdarzeń:
Pamiętaj, że możesz napotkać problemy z wydajnością. Odpowiednio wyreguluj przepustnicę. 16 zapewnia najwięcej aktualizacji. 0 tylko jeden.
źródło
function(event) { }
.scrollEventThrottle={16}
nie nie daje „less” aktualizacje; dowolna liczba z zakresu 1-16 daje maksymalną możliwą szybkość aktualizacji. Wartość domyślna 0 daje (w iOS) jedno zdarzenie, gdy użytkownik zaczyna przewijać, a następnie nie ma kolejnych aktualizacji (co jest dość bezużyteczne i prawdopodobnie jest błędem); domyślnie nie jest to „raz na klatkę”. Oprócz tych dwóch błędów w twoim komentarzu, twoje inne twierdzenia nie zaprzeczają temu, co mówi odpowiedź (chociaż wydaje ci się, że tak jest).Jeśli chcesz po prostu uzyskać bieżącą pozycję (np. Po naciśnięciu jakiegoś przycisku), zamiast śledzić ją za każdym razem, gdy użytkownik przewinie, wywołanie
onScroll
słuchacza spowoduje problemy z wydajnością. Obecnie najbardziej wydajnym sposobem uzyskania aktualnej pozycji przewijania jest użycie pakietu react-native-invoke . Jest przykład na to dokładnie, ale pakiet robi wiele innych rzeczy.Przeczytaj o tym tutaj. https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd
źródło
Aby uzyskać x / y po zakończeniu przewijania zgodnie z żądaniem oryginalnego pytania, najprostszym sposobem jest prawdopodobnie to:
źródło
onMomentumScrollEnd
jest wyzwalane tylko wtedy, gdy widok przewijania nabrał rozpędu, gdy użytkownik go puści. Jeśli zwolnią się, gdy widok przewijania się nie porusza, nigdy nie uzyskasz żadnego ze zdarzeń pędu.Powyższe odpowiedzi powiedzieć jak uzyskać pozycję przy użyciu różnych API
onScroll
,onMomentumScrollEnd
etc; Jeśli chcesz poznać indeks strony, możesz go obliczyć na podstawie wartości przesunięcia.W systemie iOS relacja między ScrollView a widocznym regionem jest następująca:
ref: https://www.objc.io/issues/3-views/scroll-view/
źródło
W ten sposób zakończyło się wyświetleniem bieżącej pozycji przewijania na żywo z widoku. Wszystko, co robię, to korzystanie z odbiornika zdarzeń on scroll i scrollEventThrottle. Następnie przekazuję to jako zdarzenie do obsługi utworzonej przeze mnie funkcji przewijania i aktualizacji moich właściwości.
źródło
użycie onScroll wchodzi w nieskończoną pętlę. Zamiast tego można użyć onMomentumScrollEnd lub onScrollEndDrag
źródło
Jeśli chodzi o stronę, pracuję nad komponentem wyższego rzędu, który używa w zasadzie powyższych metod, aby to zrobić. W rzeczywistości zajmuje to tylko trochę czasu, gdy dojdziesz do subtelności, takich jak początkowy układ i zmiany treści. Nie twierdzę, że zrobiłem to „poprawnie”, ale w pewnym sensie rozważałbym poprawną odpowiedź, używając komponentu, który robi to ostrożnie i konsekwentnie.
Zobacz: React-native-paged-scroll-view . Chciałbym otrzymać informację zwrotną, nawet jeśli zrobiłem wszystko źle!
źródło
Wierzę,
contentOffset
że da ci obiekt zawierający przesunięcie przewijania w lewym górnym rogu:http://facebook.github.io/react-native/docs/scrollview.html#contentoffset
źródło