Problem: Fragment onResume()
in ViewPager
wird ausgelöst, bevor das Fragment tatsächlich sichtbar wird.
Zum Beispiel habe ich 2 Fragmente mit ViewPager
und FragmentPagerAdapter
. Das zweite Fragment ist nur für autorisierte Benutzer verfügbar, und ich muss den Benutzer bitten, sich anzumelden, wenn das Fragment sichtbar wird (mithilfe eines Warndialogs).
ABER das ViewPager
erstellt das zweite Fragment, wenn das erste sichtbar ist, um das zweite Fragment zwischenzuspeichern, und macht es sichtbar, wenn der Benutzer mit dem Wischen beginnt.
Das onResume()
Ereignis wird also im zweiten Fragment ausgelöst, lange bevor es sichtbar wird. Aus diesem Grund versuche ich, ein Ereignis zu finden, das ausgelöst wird, wenn das zweite Fragment sichtbar wird, um zum richtigen Zeitpunkt einen Dialog anzuzeigen.
Wie kann das gemacht werden?
ViewPager
. In einem zweiseitigen Pager werden beide Seiten sofort geladen, ob Sie möchten oder nicht. Die Benutzererfahrung vonViewPager
soll sein, dass der Inhalt sofort nach dem Wischen da ist, nicht einige Zeit später. Aus diesem Grund wirdViewPager
eine Seite vor dem Sichtbaren initialisiert, um die Benutzererfahrung zu gewährleisten.Antworten:
Sie können durch Überschreiben der folgenden Aktionen
setUserVisibleHint
in IhrerFragment
:quelle
isResumed()
, um eine NPE zu vermeiden. Ich habe gut für mich gearbeitet.setUserVisibleHint
ist jetzt veraltetUPDATE : Die Android Support Library (Version 11) hat das Problem mit den sichtbaren Hinweisen des Benutzers endgültig behoben. Wenn Sie nun die Support Library für Fragmente verwenden, können Sie die Änderungen sicher verwenden
getUserVisibleHint()
oder überschreibensetUserVisibleHint()
, wie in Gorns Antwort beschrieben.UPDATE 1 Hier ist ein kleines Problem mit
getUserVisibleHint()
. Dieser Wert ist standardmäßigtrue
.Es kann also ein Problem auftreten, wenn Sie versuchen, es zu verwenden, bevor
setUserVisibleHint()
es aufgerufen wurde. UmonCreate
dieses Problem zu umgehen, können Sie in einer solchen Methode einen Wert festlegen .Die veraltete Antwort:
In den meisten Anwendungsfällen wird jeweils
ViewPager
nur eine Seite angezeigt. Die vorab zwischengespeicherten Fragmente werden jedoch auch in den Status "sichtbar" (tatsächlich unsichtbar) versetzt, wenn SieFragmentStatePagerAdapter
in verwendenAndroid Support Library pre-r11
.Ich überschreibe:
Um den Fokusstatus des Fragments zu erfassen, den ich für den am besten geeigneten Status der "Sichtbarkeit" halte, meinen Sie, da nur ein Fragment in ViewPager seine Menüelemente zusammen mit den Elementen der übergeordneten Aktivität platzieren kann.
quelle
true
erhalte für getUserVisibleHint (), wennonCreateOptionsMenu
es aufgerufen wird, und wennsetUserVisibleHint
es aufgerufen wird, wurde das Menü anscheinend noch nicht erstellt. Letztendlich bekomme ich zwei Optionen Menüs hinzugefügt, wenn ich nur das Menü aus dem sichtbaren Fragment haben möchte. Anregungen dazu?setUserVisibleHint
ist jetzt veraltetDies scheint das normale
onResume()
Verhalten wiederherzustellen, das Sie erwarten würden. Es funktioniert gut, wenn Sie die Home-Taste drücken, um die App zu verlassen und dann die App erneut aufzurufen.onResume()
wird nicht zweimal hintereinander aufgerufen.quelle
setUserVisibleHint
dem vorherigen AufrufonCreateView
und dassetUserVisibleHint
wird nicht aufgerufen, wenn die App in den Hintergrund und dann in den Vordergrund geht. Genial! Vielen Dank!onVisibleToUser()
Methode implementieren und diese vononResume()
und nachsetUserVisibleHint(boolean)
aufrufenonResume()
lassen, anstatt mich selbst anzurufen und Rückrufe im Lebenszyklus zu stören. Ansonsten denke ich, dass dieser Ansatz gut funktioniert, danke!Hier ist eine andere Möglichkeit
onPageChangeListener
:quelle
setUserVisibleHint()
wird manchmal vorheronCreateView()
und manchmal danach angerufen, was zu Problemen führt.Um dies zu überwinden, müssen Sie
isResumed()
auch diesetUserVisibleHint()
Methode überprüfen . Aber in diesem Fall wurde mir klarsetUserVisibleHint()
, dass er nur aufgerufen wird , wenn das Fragment wieder aufgenommen und sichtbar ist, NICHT wenn es erstellt wurde.Wenn Sie also etwas aktualisieren möchten, während Fragment ist
visible
, setzen Sie Ihre Aktualisierungsfunktion sowohl inonCreate()
als auch insetUserVisibleHint()
:UPDATE: Trotzdem
myUIUpdate()
wurde mir klar , dass manchmal zweimal aufgerufen wird. Der Grund ist, wenn Sie 3 Registerkarten haben und dieser Code sich auf der zweiten Registerkarte befindet. Wenn Sie die erste Registerkarte zum ersten Mal öffnen, wird auch die zweite Registerkarte erstellt, auch wenn sie nicht sichtbar ist undmyUIUpdate()
aufgerufen wird. Wenn Sie dann zur zweiten Registerkarte wischen, wirdmyUIUpdate()
fromif (visible && isResumed())
aufgerufen und wird dahermyUIUpdate()
möglicherweise zweimal in einer Sekunde aufgerufen.Das andere Problem besteht
!visible
darinsetUserVisibleHint
, sowohl 1) beim Verlassen des Fragmentbildschirms als auch 2) vor dem Erstellen aufgerufen zu werden, wenn Sie zum ersten Mal zum Fragmentbildschirm wechseln.Lösung:
Erläuterung:
fragmentResume
,fragmentVisible
: Stellt sicher , dassmyUIUpdate()
inonCreateView()
nur aufgerufen wird, wenn ein Fragment erstellt und sichtbar ist, nicht beim Fortsetzen. Es löst auch das Problem, wenn Sie sich auf der ersten Registerkarte befinden. Die zweite Registerkarte wird erstellt, auch wenn sie nicht sichtbar ist. Dies löst das und prüft, ob der Fragmentbildschirm wann sichtbar istonCreate
.fragmentOnCreated
: Stellt sicher, dass das Fragment nicht sichtbar ist und beim ersten Erstellen des Fragments nicht aufgerufen wird. Diese if-Klausel wird jetzt nur aufgerufen, wenn Sie aus dem Fragment wischen.Aktualisieren Sie setzen können alle diesen Code in
BaseFragment
Code wie folgt aus und überschreiben Methode.quelle
setUserVisibleHint
wurde kein Aufruf abgerufen . ! und innerhalb deronCreateView
MethodefragmentVisible
war dasfalse
!? so zeigte sich das Fragment leer ..! irgendwelche Gedanken.Um festzustellen ,
Fragment
inViewPager
sichtbar, ich bin ziemlich sicher , dass nur mitsetUserVisibleHint
nicht genug.Hier ist meine Lösung, um zu überprüfen, ob ein Fragment sichtbar oder unsichtbar ist. Wechseln Sie beim Starten von Viewpager zunächst zwischen den Seiten und wechseln Sie zu einer anderen Aktivität / Fragment / Hintergrund / Vordergrund`
ERLÄUTERUNG Sie können den Logcat unten sorgfältig prüfen, dann wissen Sie vielleicht, warum diese Lösung funktioniert
Erster Start
Gehen Sie zu Seite 2
Gehen Sie zu Seite 3
Zum Hintergrund gehen:
Gehe in den Vordergrund
DEMO-Projekt hier
Hoffe es hilft
quelle
SubChildContainerFragment
wird zum Erkennen verwendeta fragment has another view pager which also consists fragment
. Sie könnenSubChildContainerFragment
undChildContainerFragment
zu 1 Klasse mischen . Hoffe es hilft. Ich werde die vollständige Antwort später veröffentlichenquelle
setUserVisibleHint
VeraltetIn
ViewPager2
undViewPager
ab Version könnenandroidx.fragment:fragment:1.1.0
Sie einfachonPause
undonResume
Rückrufe verwenden, um zu bestimmen, welches Fragment derzeit für den Benutzer sichtbar ist.onResume
Rückruf wird aufgerufen, wenn das Fragment sichtbar wurde undonPause
wenn es nicht mehr sichtbar ist.Im Fall von ViewPager2 ist dies das Standardverhalten, aber das gleiche Verhalten kann für alte Güter
ViewPager
leicht aktiviert werden.Um dieses Verhalten im ersten ViewPager zu aktivieren, müssen Sie den
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
Parameter als zweites Argument desFragmentPagerAdapter
Konstruktors übergeben.Hinweis:
setUserVisibleHint()
Methode undFragmentPagerAdapter
Konstruktor mit einem Parameter sind in der neuen Version von Fragment von Android Jetpack jetzt veraltet.quelle
setPrimaryItem()
In derFragmentPagerAdapter
Unterklasse überschreiben . Ich benutze diese Methode und sie funktioniert gut.quelle
Überschreiben Sie
Fragment.onHiddenChanged()
dafür.quelle
Ich habe das herausgefunden
onCreateOptionsMenu
undonPrepareOptionsMenu
Methoden nur im Fall des wirklich sichtbaren Fragments aufgerufen . Ich konnte keine Methode finden, die sich so verhält. Ich habeOnPageChangeListener
es auch versucht, aber es hat in den Situationen nicht funktioniert. Ich benötige beispielsweise eine in deronCreate
Methode initialisierte Variable .Diese beiden Methoden können daher für dieses Problem als Problemumgehung verwendet werden, insbesondere für kleine und kurze Jobs.
Ich denke, das ist die bessere Lösung, aber nicht die beste. Ich werde dies verwenden, aber gleichzeitig auf eine bessere Lösung warten.
Grüße.
quelle
Eine andere hier veröffentlichte Lösung, die setPrimaryItem im Pageradapter von kris larson überschreibt, hat fast für mich funktioniert. Diese Methode wird jedoch für jedes Setup mehrmals aufgerufen. Außerdem habe ich NPE aus Ansichten usw. im Fragment erhalten, da dies beim ersten Aufruf dieser Methode noch nicht fertig ist. Mit den folgenden Änderungen hat dies bei mir funktioniert:
quelle
Fügen Sie den folgenden Code in das Fragment ein
quelle
Ich habe das gleiche Problem beim Arbeiten mit
FragmentStatePagerAdapters
und 3 Registerkarten festgestellt. Ich musste einen Dilaog anzeigen, wenn auf die erste Registerkarte geklickt wurde, und ihn beim Klicken auf andere Registerkarten ausblenden.Das Überschreiben
setUserVisibleHint()
allein half nicht, das aktuell sichtbare Fragment zu finden.Beim Klicken von der 3. Registerkarte -----> 1. Registerkarte. Es wurde zweimal für das 2. Fragment und für das 1. Fragment ausgelöst. Ich habe es mit der Methode isResumed () kombiniert.
quelle
Wir haben einen Sonderfall mit MVP, in dem das Fragment den Präsentator benachrichtigen muss, dass die Ansicht sichtbar geworden ist, und der Präsentator von Dagger in injiziert wird
fragment.onAttach()
.setUserVisibleHint()
ist nicht genug, wir haben 3 verschiedene Fälle entdeckt, die behoben werden mussten (onAttach()
wird erwähnt, damit Sie wissen, wann der Moderator verfügbar ist):Das Fragment wurde gerade erstellt. Das System führt folgende Aufrufe durch:
Fragment bereits erstellt und Home-Taste gedrückt. Wenn Sie die App im Vordergrund wiederherstellen, wird dies wie folgt aufgerufen:
Orientierungsänderung:
Wir möchten, dass der Sichtbarkeitshinweis nur einmal beim Präsentator eingeht. So machen wir das:
quelle
Erkennen durch
focused view
!Das funktioniert bei mir
quelle
Dieses Problem trat auf, als ich versuchte, einen Timer zum Auslösen zu bringen, wenn das Fragment im Viewpager auf dem Bildschirm angezeigt wurde, damit der Benutzer es sehen konnte.
Der Timer wurde immer gestartet, bevor das Fragment vom Benutzer gesehen wurde. Dies liegt daran, dass die
onResume()
Methode im Fragment aufgerufen wird, bevor wir das Fragment sehen können.Meine Lösung bestand darin, die
onResume()
Methode zu überprüfen . Ich wollte eine bestimmte Methode 'foo ()' aufrufen, wenn Fragment 8 das aktuelle Fragment des View Pagers war.Hoffe das hilft. Ich habe dieses Problem oft gesehen. Dies scheint die einfachste Lösung zu sein, die ich je gesehen habe. Viele andere sind nicht mit niedrigeren APIs usw. kompatibel.
quelle
Ich hatte das gleiche Problem.
ViewPager
führt andere Fragmentlebenszyklusereignisse aus und ich konnte dieses Verhalten nicht ändern. Ich habe einen einfachen Pager mit Fragmenten und verfügbaren Animationen geschrieben. SimplePagerquelle
Ich habe das benutzt und es hat funktioniert!
quelle
Ich unterstütze SectionsPagerAdapter mit untergeordneten Fragmenten, so dass ich nach vielen Kopfschmerzen endlich eine Arbeitsversion bekam, die auf Lösungen aus diesem Thema basiert:
quelle
Beachten Sie, dass
setUserVisibleHint(false)
dies bei Aktivität / Fragmentstopp nicht aufgerufen wird. Sie müssen noch Start / Stopp überprüfen, umregister/unregister
alle Listener / etc.Außerdem erhalten Sie,
setUserVisibleHint(false)
wenn Ihr Fragment in einem nicht sichtbaren Zustand beginnt. Sie möchtenunregister
dort nicht, da Sie sich in diesem Fall noch nie registriert haben.quelle
Eine einfache Methode zur Implementierung besteht darin, zu überprüfen, ob der Benutzer angemeldet ist, bevor Sie zum Fragment wechseln.
In Ihrer MainActivity können Sie so etwas in der onNavigationItemSelected- Methode ausführen .
Wenn Sie jedoch eine Navigationsleiste verwenden, wurde die Auswahl in der Schublade in Profil geändert, obwohl wir nicht zum Profilformat gegangen sind.
Um die Auswahl auf die aktuelle Auswahl zurückzusetzen, führen Sie den folgenden Code aus
quelle
Ich habe die Count-Methode des zugeordneten FragmentStatePagerAdapter überschrieben und die Gesamtanzahl abzüglich der Anzahl der auszublendenden Seiten zurückgegeben:
Wenn dem ViewPager zunächst 3 Fragmente hinzugefügt wurden und nur die ersten 2 angezeigt werden sollen, bis eine bestimmte Bedingung erfüllt ist, überschreiben Sie die Seitenzahl, indem Sie TrimmedPages auf 1 setzen, und es sollten nur die ersten beiden Seiten angezeigt werden.
Dies funktioniert gut für Seiten am Ende, hilft aber nicht wirklich für Seiten am Anfang oder in der Mitte (obwohl es viele Möglichkeiten gibt, dies zu tun).
quelle