Problem: Fragment onResume()
w ViewPager
wypala przed fragment staje się rzeczywiście widoczne.
Na przykład mam 2 fragmenty z ViewPager
i FragmentPagerAdapter
. Drugi fragment jest dostępny tylko dla autoryzowanych użytkowników i muszę poprosić użytkownika o zalogowanie się, gdy fragment stanie się widoczny (za pomocą okna dialogowego alertu).
ALE ViewPager
tworzy drugi fragment, gdy pierwszy jest widoczny, aby buforować drugi fragment i sprawia, że jest widoczny, gdy użytkownik zaczyna przesuwać.
Tak więc onResume()
zdarzenie jest uruchamiane w drugim fragmencie na długo zanim stanie się widoczne. Właśnie dlatego próbuję znaleźć zdarzenie, które zostanie uruchomione, gdy drugi fragment stanie się widoczny, aby w odpowiednim momencie pokazać okno dialogowe.
Jak można to zrobić?
ViewPager
. W dwustronicowym pagerze obie strony zostaną załadowane natychmiast, czy ci się to podoba, czy nie. Doświadczenie użytkownikaViewPager
powinno polegać na tym, że treść jest tam natychmiast po przesunięciu, a nie jakiś czas później. DlategoViewPager
inicjuje stronę przed tym, co jest widoczne, aby zapewnić wygodę użytkowania.Odpowiedzi:
Można wykonać następujące czynności nadrzędnymi
setUserVisibleHint
w twojejFragment
:źródło
isResumed()
aby uniknąć NPE. Działa mi dobrze.setUserVisibleHint
jest teraz przestarzałeAKTUALIZACJA : Android Support Library (rev 11) w końcu naprawił problem z widoczną wskazówką dla użytkownika , teraz jeśli używasz biblioteki wsparcia dla fragmentów, możesz bezpiecznie użyć
getUserVisibleHint()
lub zastąpić,setUserVisibleHint()
aby przechwycić zmiany zgodnie z opisem w odpowiedzi Gorn.AKTUALIZACJA 1 Oto jeden mały problem z
getUserVisibleHint()
. Ta wartość jest domyślnietrue
.Może więc występować problem, gdy próbujesz go użyć przed
setUserVisibleHint()
wywołaniem. Aby obejśćonCreate
ten problem, możesz ustawić wartość w metodzie takiej jak ta.Nieaktualna odpowiedź:
W większości przypadków użycia,
ViewPager
tylko pokazać jedną stronę na raz, ale wstępnie buforowane fragmenty są również umieścić na „widoczny” (w rzeczywistości niewidzialnej stanu), jeśli używaszFragmentStatePagerAdapter
wAndroid Support Library pre-r11
.Zastępuję:
Aby uchwycić stan skupienia fragmentu, który moim zdaniem jest najbardziej odpowiednim stanem „widoczności”, masz na myśli, ponieważ tylko jeden fragment w ViewPager może faktycznie umieścić elementy menu razem z elementami działania rodzica.
źródło
true
funkcję getUserVisibleHint (), kiedyonCreateOptionsMenu
jest wywoływana, a kiedysetUserVisibleHint
jest wywoływana, wydaje się, że menu nie zostało jeszcze utworzone. Ostatecznie dostaję dwie opcje Menu dodane, gdy chcę tylko menu z widocznego fragmentu. Wszelkie sugestie w tym zakresie?setUserVisibleHint
jest już przestarzałeWydaje się, że przywraca to normalne
onResume()
zachowanie, którego można się spodziewać. Dobrze się gra, naciskając klawisz Home, aby wyjść z aplikacji, a następnie ponownie wchodząc do aplikacji.onResume()
nie jest wywoływany dwa razy z rzędu.źródło
setUserVisibleHint
wywoływaniem wcześniejonCreateView
isetUserVisibleHint
nie jest wywoływane, jeśli aplikacja przechodzi w tło, a następnie na pierwszym planie. Niesamowite! Dziękuję Ci!onVisibleToUser()
metodę i wywołać ją zonResume()
i odsetUserVisibleHint(boolean)
zamiast wywoływaćonResume()
siebie i zakłócać wywołania zwrotne w cyklu życia. W przeciwnym razie myślę, że to podejście działa dobrze, dzięki!Oto inny sposób użycia
onPageChangeListener
:źródło
setUserVisibleHint()
jest wywoływany czasami przed,onCreateView()
a czasem po którym powoduje problemy.Aby temu zaradzić trzeba sprawdzić
isResumed()
, jak również wewnątrzsetUserVisibleHint()
metody. Ale w tym przypadku zdałem sobie sprawę, żesetUserVisibleHint()
zostanie wywołane tylko wtedy, gdy Fragment zostanie wznowiony i będzie widoczny, NIE po utworzeniu.Więc jeśli chcesz zaktualizować gdy fragment jest czymś
visible
, umieścić zarówno w funkcji aktualizacjionCreate()
isetUserVisibleHint()
:AKTUALIZACJA: Nadal zdaję sobie sprawę
myUIUpdate()
, że czasami wywoływane są dwa razy, ponieważ jeśli masz 3 karty, a ten kod znajduje się na drugiej karcie, po pierwszym otwarciu pierwszej karty tworzona jest również druga karta, nawet jeśli nie jest widoczna imyUIUpdate()
jest wywoływana. Następnie po przesunięciu do drugiej zakładki wywoływana jest opcjamyUIUpdate()
from ,if (visible && isResumed())
w wyniku czegomyUIUpdate()
może zostać wywołana dwukrotnie w ciągu sekundy.Drugim problemem jest
!visible
wsetUserVisibleHint
momęcie zarówno 1), gdy wyjdziesz z fragmentu ekranu i 2), zanim zostanie utworzony, po przełączeniu na ekranie fragment raz pierwszy.Rozwiązanie:
Wyjaśnienie:
fragmentResume
,fragmentVisible
: Sprawia, żemyUIUpdate()
inonCreateView()
jest wywoływane tylko wtedy, gdy fragment jest tworzony i widoczny, a nie przy wznowieniu. Rozwiązuje również problem, gdy jesteś na 1. karcie, 2. karta jest tworzona, nawet jeśli nie jest widoczna. To rozwiązuje i sprawdza, czy fragment ekranu jest widoczny, kiedyonCreate
.fragmentOnCreated
: Sprawia, że fragment nie jest widoczny i nie jest wywoływany przy pierwszym utworzeniu fragmentu. Więc teraz, jeśli klauzula zostanie wywołana tylko po przesunięciu fragmentu.Aktualizacja Możesz umieścić cały ten kod w
BaseFragment
kodzie takim jak ten i zastąpić metodę.źródło
setUserVisibleHint
nie została wywołana. ! a wewnątrzonCreateView
metodyfragmentVisible
byłofalse
! więc fragment okazał się pusty ...! jakieś pomysły.?Aby wykryć
Fragment
w trybieViewPager
widzialnym, jestem całkiem pewien, że samo użyciesetUserVisibleHint
nie wystarczy.Oto moje rozwiązanie, aby sprawdzić, czy fragment jest widoczny czy niewidoczny. Najpierw podczas uruchamiania viewpager'a przełączaj się między stronami, przejdź do innego działania / fragmentu / tła / pierwszego planu`
WYJAŚNIENIE Możesz dokładnie sprawdzić logcat poniżej, więc myślę, że możesz wiedzieć, dlaczego to rozwiązanie będzie działać
Pierwsze uruchomienie
Idź do strony 2
Idź do strony 3
Idź do tła:
Idź do pierwszego planu
Projekt DEMO tutaj
Mam nadzieję, że to pomoże
źródło
SubChildContainerFragment
służy do wykrywaniaa fragment has another view pager which also consists fragment
. Możesz mieszaćSubChildContainerFragment
iChildContainerFragment
do 1 klasy. Mam nadzieję, że to pomoże. Pełną odpowiedź opublikuję późniejźródło
setUserVisibleHint
PrzestarzałeW wersji
ViewPager2
iViewPager
od wersjiandroidx.fragment:fragment:1.1.0
możesz po prostu użyćonPause
ionResume
wywołań zwrotnych, aby określić, który fragment jest obecnie widoczny dla użytkownika.onResume
wywołanie zwrotne jest wywoływane, gdy fragment staje się widoczny ionPause
kiedy przestaje być widoczny.W przypadku ViewPager2 jest to zachowanie domyślne, ale to samo zachowanie można łatwo włączyć dla starego dobra
ViewPager
.Aby włączyć to zachowanie w pierwszym programie ViewPager, musisz przekazać
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
parametr jako drugi argumentFragmentPagerAdapter
konstruktora.Uwaga:
setUserVisibleHint()
metoda iFragmentPagerAdapter
konstruktor z jednym parametrem są teraz przestarzałe w nowej wersji Fragment z Android Jetpack.źródło
Zastąp
setPrimaryItem()
wFragmentPagerAdapter
podklasie. Używam tej metody i działa dobrze.źródło
Zastąp
Fragment.onHiddenChanged()
to.źródło
Zrozumiałem to
onCreateOptionsMenu
ionPrepareOptionsMenu
metody wywoływane tylko w przypadku fragmentu są naprawdę widoczne. Nie mogłem znaleźć żadnej metody, która zachowuje się w ten sposób, również próbowałem,OnPageChangeListener
ale to nie zadziałało w sytuacjach, na przykład potrzebuję zmiennej zainicjowanej wonCreate
metodzie.Tak więc te dwie metody można zastosować w przypadku tego problemu jako obejścia, szczególnie w przypadku małych i krótkich zadań.
Myślę, że to lepsze rozwiązanie, ale nie najlepsze. Wykorzystam to, ale jednocześnie poczekam na lepsze rozwiązanie.
Pozdrowienia.
źródło
Inne rozwiązanie zamieszczone tutaj, nadpisujące setPrimaryItem w pageradapter autorstwa Krisa Larsona, prawie dla mnie zadziałało. Ale ta metoda jest wywoływana wiele razy dla każdej konfiguracji. Dostałem także NPE z widoków itp. W tym fragmencie, ponieważ nie jest to gotowe przy pierwszych kilku wywołaniach tej metody. Przy następujących zmianach zadziałało to dla mnie:
źródło
Dodaj następujący kod do fragmentu
źródło
Napotkałem ten sam problem podczas pracy z
FragmentStatePagerAdapters
3 kartami. Musiałem pokazywać Dilaoga za każdym razem, gdy pierwsza karta została kliknięta, i ukrywać ją, klikając inne karty.Samo zastąpienie
setUserVisibleHint()
nie pomogło znaleźć bieżącego widocznego fragmentu.Po kliknięciu z 3. zakładki -----> 1. zakładka. Uruchomił się dwukrotnie dla 2. fragmentu i 1. fragmentu. Połączyłem go z metodą isResumed ().
źródło
Mamy specjalny przypadek z MVP, w którym fragment musi powiadomić prezentera, że widok stał się widoczny, a prezenter jest wstrzykiwany przez Sztylet
fragment.onAttach()
.setUserVisibleHint()
to za mało, wykryliśmy 3 różne przypadki, które wymagały rozwiązania (onAttach()
zostało wspomniane, abyś wiedział, kiedy prezenter jest dostępny):Fragment właśnie został utworzony. System wykonuje następujące połączenia:
Fragment został już utworzony i naciśnięto przycisk Home. Podczas przywracania aplikacji na pierwszym planie jest to nazywane:
Zmiana orientacji:
Chcemy, aby wskazówka widoczności dotarła do prezentera tylko raz, więc tak to robimy:
źródło
Wykrywanie przez
focused view
!To działa dla mnie
źródło
Napotkałem ten problem, gdy próbowałem uruchomić licznik czasu, gdy fragment w przeglądarce był na ekranie, aby użytkownik mógł go zobaczyć.
Timer zawsze zaczynał się tuż przed wyświetleniem fragmentu przez użytkownika. Jest tak, ponieważ
onResume()
metoda w fragmencie jest wywoływana, zanim zobaczymy fragment.Moim rozwiązaniem było sprawdzenie
onResume()
metody. Chciałem nazwać określoną metodę „foo ()”, gdy fragment 8 był bieżącym fragmentem stronicowania.Mam nadzieję że to pomoże. Często widziałem ten problem. To wydaje się być najprostszym rozwiązaniem, jakie widziałem. Wiele innych nie jest kompatybilnych z niższymi interfejsami API itp.
źródło
Miałem ten sam problem.
ViewPager
wykonuje inne fragmenty cyklu życia i nie mogłem tego zmienić. Napisałem prosty pager, używając fragmentów i dostępnych animacji. SimplePagerźródło
Użyłem tego i zadziałało!
źródło
Wspieram SectionsPagerAdapter fragmentami potomnymi, więc po dużym bólu głowy w końcu dostałem działającą wersję opartą na rozwiązaniach z tego tematu:
źródło
Zauważ, że
setUserVisibleHint(false)
nie jest wywoływane przy zatrzymaniu aktywności / fragmentu. Nadal będziesz musiał sprawdzić start / stop, aby poprawnieregister/unregister
słuchać wszystkich słuchaczy / etc.Otrzymasz również,
setUserVisibleHint(false)
jeśli twój fragment zaczyna się w niewidocznym stanie; nie chceszunregister
tam być, ponieważ nigdy wcześniej się nie rejestrowałeś.źródło
Prostym sposobem implementacji jest sprawdzenie, czy użytkownik jest zalogowany przed przejściem do fragmentu.
W swojej MainActivity możesz zrobić coś takiego w metodzie onNavigationItemSelected .
Jeśli jednak używasz szuflady nawigacji, wybór w szufladzie zmieni się na Profil, chociaż nie poszliśmy do ProfileFragment.
Aby zresetować wybór do bieżącego wyboru, uruchom poniższy kod
źródło
Przesłoniłem metodę Count powiązanego fragmentu FragmentStatePagerAdapter i zwróciłem całkowitą liczbę minus liczba stron do ukrycia:
Tak więc, jeśli początkowo dodano 3 fragmenty do ViewPager i tylko pierwsze 2 powinny być wyświetlane, dopóki nie zostanie spełniony jakiś warunek, zastąp liczbę stron, ustawiając TrimmedPages na 1 i powinny pokazywać tylko dwie pierwsze strony.
Działa to dobrze w przypadku stron na końcu, ale tak naprawdę nie pomaga w przypadku stron na początku lub w środku (chociaż istnieje wiele sposobów na zrobienie tego).
źródło