Problema: El fragmento onResume()
de ViewPager
se dispara antes de que el fragmento se convierte en realidad visible.
Por ejemplo, tengo 2 fragmentos con ViewPager
y FragmentPagerAdapter
. El segundo fragmento solo está disponible para usuarios autorizados y necesito pedirle al usuario que inicie sesión cuando el fragmento esté visible (usando un diálogo de alerta).
PERO ViewPager
crea el segundo fragmento cuando el primero es visible para almacenar en caché el segundo fragmento y lo hace visible cuando el usuario comienza a deslizar.
Entonces, el onResume()
evento se dispara en el segundo fragmento mucho antes de que sea visible. Es por eso que estoy tratando de encontrar un evento que se active cuando el segundo fragmento se haga visible para mostrar un diálogo en el momento apropiado.
¿Cómo se puede hacer esto?
ViewPager
. En un buscapersonas de dos páginas, ambas páginas se cargarán inmediatamente, te guste o no. SeViewPager
supone que la experiencia del usuario es que el contenido está allí inmediatamente al deslizar, no un tiempo después. Es por eso queViewPager
inicializa una página antes de lo que es visible, para ayudar a garantizar la experiencia del usuario.Respuestas:
Puede hacer lo siguiente anulando
setUserVisibleHint
en suFragment
:fuente
isResumed()
para evitar un NPE. He estado trabajando bien para mí.setUserVisibleHint
ahora está en desusoACTUALIZACIÓN : Android Support Library (rev 11) finalmente solucionó el problema de la sugerencia visible del usuario , ahora si usa la biblioteca de soporte para fragmentos, puede usar
getUserVisibleHint()
o anular de forma segurasetUserVisibleHint()
para capturar los cambios como se describe en la respuesta de Gorn.ACTUALIZACIÓN 1 Aquí hay un pequeño problema con
getUserVisibleHint()
. Este valor es por defectotrue
.Por lo tanto, puede haber un problema cuando intenta usarlo antes de que
setUserVisibleHint()
se invoque. Como solución alternativa, puede establecer un valor en unonCreate
método como este.La respuesta desactualizada:
En la mayoría de los casos de uso,
ViewPager
sólo se mostrará una página a la vez, pero los fragmentos pre-caché también se ponen a estado "visible" (en realidad invisible) si está utilizandoFragmentStatePagerAdapter
enAndroid Support Library pre-r11
.Anulo:
Para capturar el estado de enfoque del fragmento, que creo que es el estado más adecuado de la "visibilidad" que quiere decir, ya que solo un fragmento en ViewPager puede colocar sus elementos de menú junto con los elementos de la actividad principal.
fuente
true
getUserVisibleHint () cuandoonCreateOptionsMenu
se llama, y cuandosetUserVisibleHint
se llama, el menú aún no se ha creado, parece. Finalmente, obtengo dos opciones de Menú agregado cuando solo quiero que el menú sea visible desde el fragmento. ¿Alguna sugerencia al respecto?setUserVisibleHint
ahora está en desusoEsto parece restaurar el
onResume()
comportamiento normal que cabría esperar. Se juega bien presionando la tecla de inicio para salir de la aplicación y luego volver a ingresar a la aplicación.onResume()
no se llama dos veces seguidas.fuente
setUserVisibleHint
ser llamado antesonCreateView
ysetUserVisibleHint
no se llama si la aplicación pasa a segundo plano y luego a primer plano. ¡Increíble! ¡Gracias!onVisibleToUser()
método simple y hacer que se llame desdeonResume()
y desde ensetUserVisibleHint(boolean)
lugar de llamarmeonResume()
e interferir con las devoluciones de llamada del ciclo de vida. De lo contrario, creo que este enfoque funciona bien, ¡gracias!Aquí hay otra forma de usar
onPageChangeListener
:fuente
setUserVisibleHint()
se llama a veces antesonCreateView()
y a veces después de lo cual causa problemas.Para superar esto, debe verificar
isResumed()
también elsetUserVisibleHint()
método interno . Pero en este caso, me di cuenta de que solosetUserVisibleHint()
se llama si Fragment se reanuda y es visible, NO cuando se crea.Entonces, si desea actualizar algo cuando Fragment es
visible
, coloque su función de actualización enonCreate()
ysetUserVisibleHint()
:ACTUALIZACIÓN: Todavía me di cuenta de que a
myUIUpdate()
veces se llama dos veces, la razón es que si tiene 3 pestañas y este código está en la segunda pestaña, cuando abre la primera pestaña, la segunda pestaña también se crea, incluso si no es visible ymyUIUpdate()
se llama. Luego, cuando desliza a la segunda pestaña,myUIUpdate()
desdeif (visible && isResumed())
se llama y, como resultado,myUIUpdate()
puede llamarse dos veces en un segundo.El otro problema es
!visible
ensetUserVisibleHint
obtiene la llamada tanto 1) cuando sale de la pantalla y el fragmento 2) antes de que se crea, cuando se cambia a la pantalla fragmento primera vez.Solución:
Explicación:
fragmentResume
,fragmentVisible
: Se aseguramyUIUpdate()
de queonCreateView()
se invoca solo cuando se crea un fragmento y está visible, no en el currículum. También resuelve el problema cuando está en la primera pestaña, la segunda pestaña se crea incluso si no está visible. Esto resuelve eso y comprueba si la pantalla de fragmentos es visible cuandoonCreate
.fragmentOnCreated
: Se asegura de que el fragmento no sea visible y no se llame cuando se crea un fragmento por primera vez. Así que ahora esta cláusula if solo se llama cuando deslizas el fragmento.Actualización Puede poner todo este código en un
BaseFragment
código como este y anular el método.fuente
setUserVisibleHint
no recibió llamada. ! y dentro delonCreateView
métodofragmentVisible
fuefalse
! entonces el fragmento apareció vacío ...! Alguna idea.?Para detectar
Fragment
enViewPager
visible, estoy bastante seguro de que solo usarsetUserVisibleHint
no es suficiente.Aquí está mi solución para verificar si un fragmento es visible o invisible. Primero, cuando inicie el visor, cambie de página, vaya a otra actividad / fragmento / fondo / primer plano`
EXPLICACIÓN Puede verificar cuidadosamente el logcat a continuación, luego creo que puede saber por qué funcionará esta solución
Primer lanzamiento
Ir a la página2
Ir a la página 3
Ir al fondo:
Ir al primer plano
Proyecto DEMO aquí
Espero que ayude
fuente
SubChildContainerFragment
se utiliza para detectara fragment has another view pager which also consists fragment
. Puedes mezclarSubChildContainerFragment
yaChildContainerFragment
1 clase. Espero que sea de ayuda. Publicaré la respuesta completa más tardefuente
setUserVisibleHint
EnEn
ViewPager2
yViewPager
desde la versiónandroidx.fragment:fragment:1.1.0
, puede usaronPause
yonResume
devoluciones de llamada para determinar qué fragmento es actualmente visible para el usuario.onResume
Se llama a la devolución de llamada cuando el fragmento se hizo visible yonPause
cuando deja de ser visible.En el caso de ViewPager2, es un comportamiento predeterminado, pero el mismo comportamiento se puede habilitar para el bien antiguo
ViewPager
fácilmente.Para habilitar este comportamiento en el primer ViewPager, debe pasar el
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
parámetro como segundo argumento delFragmentPagerAdapter
constructor.Nota: el
setUserVisibleHint()
método y elFragmentPagerAdapter
constructor con un parámetro ahora están en desuso en la nueva versión de Fragment de android jetpack.fuente
Anulación
setPrimaryItem()
en laFragmentPagerAdapter
subclase. Yo uso este método, y funciona bien.fuente
Anular
Fragment.onHiddenChanged()
por eso.fuente
Me di cuenta de eso
onCreateOptionsMenu
y losonPrepareOptionsMenu
métodos llamados solo en el caso del fragmento realmente visible. No pude encontrar ningún método que se comportara así, también lo intentéOnPageChangeListener
pero no funcionó para las situaciones, por ejemplo, necesito una variable inicializada enonCreate
método.Por lo tanto, estos dos métodos se pueden usar para este problema como una solución alternativa, específicamente para trabajos pequeños y cortos.
Creo que esta es la mejor solución, pero no la mejor. Usaré esto pero espero una mejor solución al mismo tiempo.
Saludos.
fuente
Otra solución publicada aquí anulando setPrimaryItem en el pageradapter por kris larson casi me funcionó. Pero este método se llama varias veces para cada configuración. También obtuve NPE de vistas, etc. en el fragmento ya que esto no está listo las primeras veces que se llama a este método. Con los siguientes cambios esto funcionó para mí:
fuente
Agregue el siguiente código dentro del fragmento
fuente
Encontré el mismo problema mientras trabajaba con
FragmentStatePagerAdapters
3 pestañas. Tenía que mostrar un Dilaog cada vez que se hacía clic en la primera pestaña y ocultarlo al hacer clic en otras pestañas.Anular
setUserVisibleHint()
solo no ayudó a encontrar el fragmento visible actual.Al hacer clic desde la tercera pestaña -----> primera pestaña. Se activó dos veces para el segundo fragmento y para el primer fragmento. Lo combiné con el método isResumed ().
fuente
Tenemos un caso especial con MVP donde el fragmento debe notificar al presentador que la vista se ha vuelto visible, y Dagger inyecta al presentador
fragment.onAttach()
.setUserVisibleHint()
no es suficiente, hemos detectado 3 casos diferentes que debían abordarse (onAttach()
se menciona para que sepa cuándo está disponible el presentador):Fragmento acaba de ser creado. El sistema realiza las siguientes llamadas:
Fragmento ya creado y se presiona el botón de inicio. Al restaurar la aplicación a primer plano, esto se llama:
Cambio de orientación:
Solo queremos que la pista de visibilidad llegue al presentador una vez, así que así es como lo hacemos:
fuente
Detectando por
focused view
!Esto funciona para mi
fuente
Encontré este problema cuando intentaba que se disparara un temporizador cuando el fragmento en el visor estaba en la pantalla para que el usuario lo viera.
El temporizador siempre comenzó justo antes de que el usuario viera el fragmento. Esto se debe
onResume()
a que se llama al método en el fragmento antes de que podamos ver el fragmento.Mi solución fue verificar el
onResume()
método. Quería llamar a cierto método 'foo ()' cuando el fragmento 8 era el fragmento actual de los buscapersonas.Espero que esto ayude. He visto surgir mucho este problema. Esta parece ser la solución más simple que he visto. Muchos otros no son compatibles con API inferiores, etc.
fuente
Tuve el mismo problema.
ViewPager
ejecuta otros fragmentos de eventos del ciclo de vida y no pude cambiar ese comportamiento. Escribí un buscapersonas simple usando fragmentos y animaciones disponibles. SimplePagerfuente
¡Usé esto y funcionó!
fuente
Apoyo SectionsPagerAdapter con fragmentos secundarios, así que después de mucho dolor de cabeza finalmente obtuve una versión funcional basada en soluciones de este tema:
fuente
Tenga en cuenta que
setUserVisibleHint(false)
no se llama en la parada de actividad / fragmento. Aún deberá verificar el inicio / detención pararegister/unregister
escuchar los oyentes / etc.Además, obtendrá
setUserVisibleHint(false)
si su fragmento comienza en un estado no visible; no quieresunregister
allí ya que nunca te has registrado antes en ese caso.fuente
Una forma sencilla de implementar es verificar si el usuario ha iniciado sesión antes de ir al fragmento.
En su MainActivity puede hacer algo como esto dentro del método onNavigationItemSelected .
Sin embargo, si está utilizando el cajón de navegación, la selección en el cajón habrá cambiado a Perfil, aunque no hemos ido al Fragmento de perfil.
Para restablecer la selección a la selección actual, ejecute el siguiente código
fuente
setUserVisibleHint (boolean visible) ahora está en desuso Así que esta es la solución correcta
En ViewPager2 y ViewPager desde la versión
androidx.fragment:fragment:1.1.0
, solo puede usaronPause()
yonResume()
determinar qué fragmento es actualmente visible para el usuario.onResume()
Se llama cuando el fragmento se hizo visible yonPause
cuando deja de ser visible.Para habilitar este comportamiento en el primer ViewPager, debe pasar el
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
parámetro como segundo argumento delFragmentPagerAdapter
constructor.fuente
Anulé el método Count del FragmentStatePagerAdapter asociado y pido que devuelva el recuento total menos el número de páginas para ocultar:
Entonces, si hay 3 fragmentos inicialmente agregados al ViewPager, y solo se deben mostrar los primeros 2 hasta que se cumpla alguna condición, anule el recuento de páginas configurando TrimmedPages en 1 y solo debería mostrar las dos primeras páginas.
Esto funciona bien para las páginas al final, pero realmente no ayudará para las que están al principio o en el medio (aunque hay muchas maneras de hacerlo).
fuente