Problème: Fragment onResume()
en ViewPager
est tiré avant que le fragment devient réellement visible.
Par exemple, j'ai 2 fragments avec ViewPager
et FragmentPagerAdapter
. Le deuxième fragment n'est disponible que pour les utilisateurs autorisés et je dois demander à l'utilisateur de se connecter lorsque le fragment devient visible (à l'aide d'une boîte de dialogue d'alerte).
MAIS le ViewPager
crée le deuxième fragment lorsque le premier est visible afin de mettre en cache le deuxième fragment et le rend visible lorsque l'utilisateur commence à glisser.
L' onResume()
événement est donc déclenché dans le deuxième fragment bien avant qu'il ne devienne visible. C'est pourquoi j'essaie de trouver un événement qui se déclenche lorsque le deuxième fragment devient visible pour afficher une boîte de dialogue au moment approprié.
Comment cela peut-il être fait?
ViewPager
. Dans un téléavertisseur de deux pages, les deux pages seront chargées immédiatement, que cela vous plaise ou non. L'expérience utilisateur deViewPager
est censée être que le contenu est là immédiatement après avoir glissé, pas un peu plus tard. C'est pourquoiViewPager
initialise une page avant ce qui est visible, pour garantir cette expérience utilisateur.Réponses:
Vous pouvez effectuer les opérations suivantes en remplaçant
setUserVisibleHint
votreFragment
:la source
isResumed()
pour éviter un NPE. Ça marche bien pour moi.setUserVisibleHint
est désormais obsolèteMISE À JOUR : Android Support Library (rev 11) a finalement corrigé le problème de l'indice visible de l'utilisateur , maintenant si vous utilisez la bibliothèque de support pour les fragments, vous pouvez utiliser
getUserVisibleHint()
ou remplacer en toute sécuritésetUserVisibleHint()
pour capturer les modifications comme décrit par la réponse de Gorn.MISE À JOUR 1 Voici un petit problème avec
getUserVisibleHint()
. Cette valeur est par défauttrue
.Il peut donc y avoir un problème lorsque vous essayez de l'utiliser avant qu'il
setUserVisibleHint()
soit invoqué. Pour contourner ce problème, vous pouvez définir une valeur dans uneonCreate
méthode comme celle-ci.La réponse obsolète:
Dans la plupart des cas d'utilisation,
ViewPager
affichez une seule page à la fois, mais les fragments pré-mis en cache sont également mis à l'état "visible" (en fait invisible) si vous utilisezFragmentStatePagerAdapter
inAndroid Support Library pre-r11
.Je remplace:
Pour capturer l'état de mise au point du fragment, ce qui, à mon avis, est l'état le plus approprié de la "visibilité", car un seul fragment dans ViewPager peut réellement placer ses éléments de menu avec les éléments de l'activité parent.
la source
true
pour getUserVisibleHint () quandonCreateOptionsMenu
est appelé, et quandsetUserVisibleHint
est appelé, le menu n'a pas encore été créé semble-t-il. En fin de compte, deux options sont ajoutées au menu lorsque je ne veux que le menu du fragment visible. Des suggestions à cet égard?setUserVisibleHint
est désormais obsolèteCela semble restaurer le
onResume()
comportement normal que vous attendez. Cela joue bien en appuyant sur la touche d'accueil pour quitter l'application, puis en entrant à nouveau dans l'application.onResume()
n'est pas appelé deux fois de suite.la source
setUserVisibleHint
être appelé avantonCreateView
et quisetUserVisibleHint
n'est pas appelé si l'application passe en arrière-plan puis au premier plan. Impressionnant! Je vous remercie!onVisibleToUser()
méthode simple et faire appel deonResume()
et verssetUserVisibleHint(boolean)
au lieu deonResume()
m'appeler et d'interférer avec les rappels du cycle de vie. Sinon, je pense que cette approche fonctionne bien, merci!Voici une autre façon d'utiliser
onPageChangeListener
:la source
setUserVisibleHint()
est appelé parfois avantonCreateView()
et parfois après, ce qui cause des problèmes.Pour surmonter cela, vous devez également vérifier la méthode
isResumed()
internesetUserVisibleHint()
. Mais dans ce cas, j'ai réalisé que je ne suissetUserVisibleHint()
appelé que si le fragment est repris et visible, PAS lors de sa création.Donc, si vous souhaitez mettre à jour quelque chose lorsque Fragment est
visible
, mettez votre fonction de mise à jour à la fois dansonCreate()
etsetUserVisibleHint()
:MISE À JOUR: Je me suis quand même rendu compte que je suis
myUIUpdate()
appelé parfois deux fois, la raison en est que si vous avez 3 onglets et que ce code est sur le 2e onglet, lorsque vous ouvrez le 1er onglet pour la première fois, le 2e onglet est également créé même s'il n'est pas visible etmyUIUpdate()
est appelé. Ensuite, lorsque vous glissez vers le 2e onglet,myUIUpdate()
deif (visible && isResumed())
est appelé et, par conséquent,myUIUpdate()
peut être appelé deux fois en une seconde.L'autre problème est
!visible
danssetUserVisibleHint
obtient appelé à la fois 1) lorsque vous sortez de l'écran de fragment et 2) avant qu'il ne soit créé, lorsque vous passez à l'écran de fragment la première fois.Solution:
Explication:
fragmentResume
,fragmentVisible
: S'assure quemyUIUpdate()
inonCreateView()
n'est appelé que lorsque le fragment est créé et visible, et non à la reprise. Il résout également le problème lorsque vous êtes au 1er onglet, le deuxième onglet est créé même s'il n'est pas visible. Cela résout cela et vérifie si l'écran de fragment est visible quandonCreate
.fragmentOnCreated
: S'assure que le fragment n'est pas visible et n'est pas appelé lorsque vous créez un fragment pour la première fois. Alors maintenant, cette clause if n'est appelée que lorsque vous glissez hors du fragment.Mise à jour Vous pouvez mettre tout ce code dans du
BaseFragment
code comme celui-ci et remplacer la méthode.la source
setUserVisibleHint
n'a pas été appelé. ! et à l'intérieur de laonCreateView
méthodefragmentVisible
étaitfalse
!? donc le fragment est apparu vide ..! Des pensées.?Pour détecter
Fragment
enViewPager
visible, je suis bien sûr que seule l'utilisationsetUserVisibleHint
n'est pas suffisante.Voici ma solution pour vérifier si un fragment est visible ou invisible. Tout d'abord lors du lancement de Viewpager, basculez entre les pages, accédez à une autre activité / fragment / arrière-plan / premier plan`
EXPLICATION Vous pouvez vérifier attentivement le logcat ci-dessous, puis je pense que vous savez peut-être pourquoi cette solution fonctionnera
Premier lancement
Aller à la page2
Aller à la page3
Aller à l'arrière-plan:
Aller au premier plan
Projet DEMO ici
J'espère que ça aide
la source
SubChildContainerFragment
est utilisé pour détectera fragment has another view pager which also consists fragment
. Vous pouvez mélangerSubChildContainerFragment
etChildContainerFragment
à 1 classe. J'espère que cela vous aidera. Je posterai la réponse complète plus tardla source
setUserVisibleHint
ObsolèteDans
ViewPager2
et àViewPager
partir de la version,androidx.fragment:fragment:1.1.0
vous pouvez simplement utiliseronPause
et desonResume
rappels pour déterminer quel fragment est actuellement visible pour l'utilisateur.onResume
le rappel est appelé lorsque le fragment est devenu visible etonPause
lorsqu'il cesse d'être visible.Dans le cas de ViewPager2, il s'agit d'un comportement par défaut, mais le même comportement peut être activé
ViewPager
facilement pour l'ancien .Pour activer ce comportement dans le premier ViewPager, vous devez passer le
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
paramètre comme deuxième argument duFragmentPagerAdapter
constructeur.Remarque: la
setUserVisibleHint()
méthode et leFragmentPagerAdapter
constructeur avec un paramètre sont désormais obsolètes dans la nouvelle version de Fragment d'Android Jetpack.la source
Remplacer
setPrimaryItem()
dans laFragmentPagerAdapter
sous - classe. J'utilise cette méthode, et cela fonctionne bien.la source
Remplacez
Fragment.onHiddenChanged()
pour cela.la source
J'ai compris cela
onCreateOptionsMenu
et lesonPrepareOptionsMenu
méthodes appelées uniquement dans le cas du fragment vraiment visible. Je n'ai trouvé aucune méthode qui se comporte comme celles-ci, j'ai également essayéOnPageChangeListener
mais cela n'a pas fonctionné pour les situations, par exemple, j'ai besoin d'une variable initialisée dansonCreate
method.Ces deux méthodes peuvent donc être utilisées pour ce problème comme solution de contournement, en particulier pour les petits et courts travaux.
Je pense que c'est la meilleure solution mais pas la meilleure. Je vais l'utiliser, mais attendre une meilleure solution en même temps.
Cordialement.
la source
Une autre solution publiée ici remplaçant setPrimaryItem dans le pageradapter par kris larson a presque fonctionné pour moi. Mais cette méthode est appelée plusieurs fois pour chaque configuration. J'ai également obtenu NPE des vues, etc. dans le fragment car ce n'est pas prêt les premières fois que cette méthode est appelée. Avec les changements suivants, cela a fonctionné pour moi:
la source
Ajouter le code suivant à l'intérieur du fragment
la source
J'ai rencontré le même problème en travaillant avec
FragmentStatePagerAdapters
et 3 onglets. Je devais montrer un Dilaog chaque fois que le premier onglet était cliqué et le cacher en cliquant sur d'autres onglets.Le dépassement
setUserVisibleHint()
seul n'a pas aidé à trouver le fragment visible actuel.En cliquant sur à partir du 3e onglet -----> 1er onglet. Il s'est déclenché deux fois pour le 2e fragment et pour le 1er fragment. Je l'ai combiné avec la méthode isResumed ().
la source
Nous avons un cas particulier avec MVP où le fragment doit informer le présentateur que la vue est devenue visible, et le présentateur est injecté par Dagger dans
fragment.onAttach()
.setUserVisibleHint()
ne suffit pas, nous avons détecté 3 cas différents qui devaient être traités (onAttach()
est mentionné pour que vous sachiez quand le présentateur est disponible):Le fragment vient d'être créé. Le système effectue les appels suivants:
Fragment déjà créé et bouton d'accueil enfoncé. Lors de la restauration de l'application au premier plan, cela s'appelle:
Changement d'orientation:
Nous voulons que l'indicateur de visibilité ne parvienne au présentateur qu'une seule fois, alors voici comment procéder:
la source
Détection par
focused view
!Ça marche pour moi
la source
J'ai rencontré ce problème lorsque j'essayais de déclencher une minuterie lorsque le fragment du viseur était à l'écran pour que l'utilisateur puisse le voir.
Le minuteur a toujours démarré juste avant que le fragment ne soit vu par l'utilisateur. C'est parce que la
onResume()
méthode dans le fragment est appelée avant que nous puissions voir le fragment.Ma solution a été de vérifier la
onResume()
méthode. Je voulais appeler une certaine méthode 'foo ()' lorsque le fragment 8 était le fragment actuel des pagers de vue.J'espère que cela t'aides. J'ai vu ce problème apparaître souvent. Cela semble être la solution la plus simple que j'ai vue. Beaucoup d'autres ne sont pas compatibles avec les API inférieures, etc.
la source
J'ai eu le même problème.
ViewPager
exécute d'autres événements de cycle de vie de fragment et je ne pouvais pas changer ce comportement. J'ai écrit un simple pager utilisant des fragments et des animations disponibles. SimplePagerla source
Je l'ai utilisé et cela a fonctionné!
la source
Je supporte SectionsPagerAdapter avec des fragments enfants, donc après beaucoup de maux de tête, j'ai finalement obtenu une version de travail basée sur des solutions de ce sujet:
la source
Notez qu'il
setUserVisibleHint(false)
n'est pas appelé à l'arrêt de l'activité / du fragment. Vous aurez toujours besoin de vérifier démarrer / arrêter correctementregister/unregister
tous les écouteurs / etc.En outre, vous obtiendrez
setUserVisibleHint(false)
si votre fragment commence dans un état non visible; vous ne voulez pasunregister
y aller puisque vous ne vous êtes jamais inscrit auparavant dans ce cas.la source
Un moyen simple d'implémentation qui consiste à vérifier si l'utilisateur est connecté avant d' accéder au fragment.
Dans votre MainActivity, vous pouvez faire quelque chose comme ça dans la méthode onNavigationItemSelected .
Cependant, si vous utilisez le tiroir de navigation, la sélection dans le tiroir aura changé pour Profile bien que nous ne soyons pas passés au ProfileFragment.
Pour réinitialiser la sélection à la sélection actuelle, exécutez le code ci-dessous
la source
setUserVisibleHint (booléen visible) est désormais obsolète. C'est donc la bonne solution
Dans ViewPager2 et ViewPager à partir de la version,
androidx.fragment:fragment:1.1.0
vous pouvez simplement utiliseronPause()
etonResume()
pour déterminer quel fragment est actuellement visible pour l'utilisateur.onResume()
est appelé lorsque le fragment est devenu visible etonPause
lorsqu'il cesse d'être visible.Pour activer ce comportement dans le premier ViewPager, vous devez passer le
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
paramètre comme deuxième argument duFragmentPagerAdapter
constructeur.la source
J'ai remplacé la méthode Count du FragmentStatePagerAdapter associé et lui ai fait retourner le nombre total moins le nombre de pages à cacher:
Donc, s'il y a 3 fragments initialement ajoutés au ViewPager et que seuls les 2 premiers doivent être affichés jusqu'à ce qu'une condition soit remplie, remplacez le nombre de pages en définissant TrimmedPages à 1 et il ne doit afficher que les deux premières pages.
Cela fonctionne bien pour les pages à la fin, mais n'aidera pas vraiment celles du début ou du milieu (bien qu'il existe de nombreuses façons de le faire).
la source