Problema: Fragmento onResume()
em ViewPager
é acionado antes do fragmento se torna realmente visível.
Por exemplo, eu tenho 2 fragmentos com ViewPager
eFragmentPagerAdapter
. O segundo fragmento está disponível apenas para usuários autorizados e preciso solicitar que o usuário efetue login quando o fragmento se tornar visível (usando uma caixa de diálogo de alerta).
Mas o ViewPager
cria o segundo fragmento quando o primeiro estiver visível para armazenar em cache o segundo fragmento e o torna visível quando o usuário começa a passar o dedo.
Então o onResume()
evento é disparado no segundo fragmento muito antes de se tornar visível. É por isso que estou tentando encontrar um evento que é acionado quando o segundo fragmento se torna visível para mostrar um diálogo no momento apropriado.
Como isso pode ser feito?
ViewPager
. Em um pager de duas páginas, as duas páginas serão carregadas imediatamente, quer você goste ou não.ViewPager
Supõe-se que a experiência do usuário seja de que o conteúdo esteja lá imediatamente após a passagem, e não algum tempo depois. É por isso queViewPager
inicializa uma página antes do que é visível, para ajudar a garantir a experiência do usuário.Respostas:
Você pode fazer o seguinte substituindo o
setUserVisibleHint
seuFragment
:fonte
isResumed()
para evitar um NPE. Está funcionando bem para mim.setUserVisibleHint
agora está obsoletoATUALIZAÇÃO : a Biblioteca de suporte do Android (rev 11) finalmente corrigiu o problema de dica visível do usuário . Agora, se você usar a biblioteca de suporte para fragmentos, poderá usar
getUserVisibleHint()
ou substituirsetUserVisibleHint()
com segurança para capturar as alterações, conforme descrito pela resposta de gorn.ATUALIZAÇÃO 1 Aqui está um pequeno problema com
getUserVisibleHint()
. Este valor é por padrãotrue
.Portanto, pode haver um problema ao tentar usá-lo antes de
setUserVisibleHint()
ser chamado. Como solução alternativa, você pode definir um valor noonCreate
método como este.A resposta desatualizada:
Na maioria dos casos de uso,
ViewPager
mostram apenas uma página de cada vez, mas os fragmentos pré-armazenados em cache também são colocados para o estado "visível" (na verdade invisível) se você estiver usandoFragmentStatePagerAdapter
noAndroid Support Library pre-r11
.Eu substituo:
Para capturar o estado de foco do fragmento, que eu acho que é o estado mais adequado para a "visibilidade" que você quer dizer, uma vez que apenas um fragmento no ViewPager pode realmente colocar seus itens de menu junto com os itens da atividade pai.
fonte
true
getUserVisibleHint () quandoonCreateOptionsMenu
é chamado e quandosetUserVisibleHint
é chamado, o menu ainda não foi criado, parece. Por fim, recebo duas opções Menu adicionado quando quero apenas o menu do fragmento visível. Alguma sugestão a esse respeito?setUserVisibleHint
agora está obsoletoIsso parece restaurar o
onResume()
comportamento normal que você esperaria. Ele funciona bem ao pressionar a tecla home para sair do aplicativo e depois entrar novamente no aplicativo.onResume()
não é chamado duas vezes seguidas.fonte
setUserVisibleHint
ser chamado antesonCreateView
e issosetUserVisibleHint
não é chamado se o aplicativo entrar em segundo plano e depois em primeiro plano. Impressionante! Obrigado!onVisibleToUser()
método simples e ter que chamar deonResume()
e de emsetUserVisibleHint(boolean)
vez deonResume()
me chamar e interferir nos retornos de chamada do ciclo de vida. Caso contrário, acho que essa abordagem funciona bem, obrigado!Aqui está outra maneira de usar
onPageChangeListener
:fonte
setUserVisibleHint()
é chamado algumas vezes antesonCreateView()
e outras depois, o que causa problemas.Para superar isso, você precisa verificar
isResumed()
também osetUserVisibleHint()
método interno . Mas, nesse caso, percebi que sósetUserVisibleHint()
é chamado se o Fragmento for retomado e visível, NÃO quando criado.Portanto, se você deseja atualizar algo quando o Fragment estiver
visible
, coloque sua função de atualização emonCreate()
esetUserVisibleHint()
:ATUALIZAÇÃO: Ainda assim, eu percebi que
myUIUpdate()
é chamado duas vezes às vezes, o motivo é que, se você tiver 3 guias e esse código estiver na 2ª guia, quando você abrir a 1ª guia, a 2ª guia também será criada, mesmo que não seja visível emyUIUpdate()
seja chamada. Então, quando você desliza para a 2ª guia,myUIUpdate()
fromif (visible && isResumed())
é chamado e, como resultado,myUIUpdate()
pode ser chamado duas vezes em um segundo.O outro problema é
!visible
emsetUserVisibleHint
é chamado tanto 1) quando você sai da tela fragmento e 2) antes de ser criado, quando você alternar para a tela fragmento primeira vez.Solução:
Explicação:
fragmentResume
,fragmentVisible
: GarantemyUIUpdate()
emonCreateView()
é chamado somente quando fragmento é criado e visível, não no currículo. Também resolve o problema quando você está na 1ª guia, a segunda guia é criada mesmo que não esteja visível. Isso resolve e verifica se a tela do fragmento está visível quandoonCreate
.fragmentOnCreated
: Garante que o fragmento não esteja visível e não seja chamado quando você criar um fragmento pela primeira vez. Então agora essa cláusula if só é chamada quando você desliza para fora do fragmento.Atualização Você pode colocar todo esse código em um
BaseFragment
código como este e substituir o método.fonte
setUserVisibleHint
, não foi chamado. ! e dentro doonCreateView
métodofragmentVisible
foifalse
!? então o fragmento apareceu vazio ..! Alguma ideia.?Para detectar
Fragment
noViewPager
visível, tenho certeza de que apenas o usosetUserVisibleHint
não é suficiente.Aqui está minha solução para verificar se um fragmento é visível ou invisível. Primeiro, ao iniciar o viewpager, alterne entre as páginas, vá para outra atividade / fragmento / fundo / primeiro plano`
EXPLICAÇÃO Você pode verificar o logcat abaixo com cuidado, então acho que você pode saber por que essa solução funcionará
Primeiro lançamento
Ir para a página2
Ir para a página3
Vá para segundo plano:
Ir para o primeiro plano
Projeto DEMO aqui
Espero que ajude
fonte
SubChildContainerFragment
é usado para detectara fragment has another view pager which also consists fragment
. Você pode misturarSubChildContainerFragment
eChildContainerFragment
para 1 aula. Espero que ajude. Postarei a resposta completa mais tarde #fonte
setUserVisibleHint
ObsoletaNa versão
ViewPager2
eViewPager
da versão,androidx.fragment:fragment:1.1.0
você pode apenas usaronPause
eonResume
retornos de chamada para determinar qual fragmento está atualmente visível para o usuário.onResume
o retorno de chamada é chamado quando o fragmento seonPause
torna visível e quando para de ficar visível.No caso do ViewPager2, é um comportamento padrão, mas o mesmo comportamento pode ser ativado para o bem antigo
ViewPager
facilmente.Para habilitar esse comportamento no primeiro ViewPager, você deve passar o
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
parâmetro como segundo argumento doFragmentPagerAdapter
construtor.Nota: o
setUserVisibleHint()
método e oFragmentPagerAdapter
construtor com um parâmetro agora estão obsoletos na nova versão do Fragment do android jetpack.fonte
Substituir
setPrimaryItem()
naFragmentPagerAdapter
subclasse. Eu uso esse método e funciona bem.fonte
Substituir
Fragment.onHiddenChanged()
por isso.fonte
Eu descobri isso
onCreateOptionsMenu
eonPrepareOptionsMenu
métodos chamados apenas no caso do fragmento realmente visível. Não encontrei nenhum método que se comporte assim, tentei,OnPageChangeListener
mas não funcionou para as situações, por exemplo, preciso de uma variável inicializada noonCreate
método.Portanto, esses dois métodos podem ser usados para esse problema como uma solução alternativa, especificamente para trabalhos pequenos e curtos.
Penso que esta é a melhor solução, mas não a melhor. Vou usar isso, mas aguardo uma solução melhor ao mesmo tempo.
Saudações.
fonte
Outra solução postada aqui, substituindo setPrimaryItem no pageradapter por kris larson, quase funcionou para mim. Mas esse método é chamado várias vezes para cada instalação. Também recebi o NPE de visualizações, etc. no fragmento, pois isso não está pronto nas primeiras vezes em que esse método é chamado. Com as seguintes alterações, isso funcionou para mim:
fonte
Adicione o seguinte código dentro do fragmento
fonte
Encontrei o mesmo problema ao trabalhar com
FragmentStatePagerAdapters
e 3 guias. Eu tive que mostrar um Dilaog sempre que a 1ª guia foi clicada e ocultá-la clicando em outras guias.A substituição
setUserVisibleHint()
sozinha não ajudou a encontrar o fragmento visível atual.Ao clicar na 3ª guia -----> 1ª guia. Foi acionado duas vezes para o 2º fragmento e para o 1º fragmento. Eu combinei com o método isResumed ().
fonte
Temos um caso especial com o MVP, em que o fragmento precisa notificar o apresentador de que a exibição se tornou visível, e o apresentador é injetado por Dagger
fragment.onAttach()
.setUserVisibleHint()
não é suficiente, detectamos três casos diferentes que precisavam ser abordados (onAttach()
é mencionado para que você saiba quando o apresentador está disponível):Fragmento acaba de ser criado. O sistema faz as seguintes chamadas:
Fragmento já criado e o botão home é pressionado. Ao restaurar o aplicativo em primeiro plano, isso é chamado:
Mudança de orientação:
Queremos que a dica de visibilidade chegue ao apresentador apenas uma vez, e é assim que fazemos:
fonte
Detectando por
focused view
!Isso funciona para mim
fonte
Encontrei esse problema quando estava tentando acionar um timer quando o fragmento no visor estava na tela para o usuário ver.
O cronômetro sempre iniciava antes do fragmento ser visto pelo usuário. Isso ocorre porque o
onResume()
método no fragmento é chamado antes que possamos ver o fragmento.Minha solução foi fazer uma verificação no
onResume()
método. Eu queria chamar um determinado método de 'foo ()' quando o fragmento 8 era o fragmento atual dos pagers de exibição.Espero que isto ajude. Eu já vi esse problema aparecer muito. Esta parece ser a solução mais simples que já vi. Muitos outros não são compatíveis com APIs mais baixas etc.
fonte
Eu tive o mesmo problema.
ViewPager
executa outros eventos do ciclo de vida do fragmento e não pude mudar esse comportamento. Escrevi um pager simples usando fragmentos e animações disponíveis. SimplePagerfonte
Eu usei isso e funcionou!
fonte
Eu apóio o SectionsPagerAdapter com fragmentos filhos. Depois de muita dor de cabeça, finalmente consegui a versão de trabalho com base nas soluções deste tópico:
fonte
Observe que
setUserVisibleHint(false)
não é chamado na parada de atividade / fragmento. Você ainda precisará verificar iniciar / parar adequadamenteregister/unregister
qualquer ouvinte / etc.Além disso, você verá
setUserVisibleHint(false)
se o seu fragmento inicia em um estado não visível; você não quer ir paraunregister
lá, porque nunca se registrou antes nesse caso.fonte
Uma maneira simples de implementar é verificar se o usuário está conectado antes de ir para o fragmento.
Em seu MainActivity, você pode fazer algo assim dentro do método onNavigationItemSelected .
No entanto, se você estiver usando a gaveta de navegação, a seleção na gaveta será alterada para Perfil, embora não tenhamos ido para o ProfileFragment.
Para redefinir a seleção para a seleção atual, execute o código abaixo
fonte
setUserVisibleHint (boolean visible) agora está obsoleto. Portanto, esta é a solução correta
No ViewPager2 e no ViewPager da versão,
androidx.fragment:fragment:1.1.0
você pode apenas usaronPause()
eonResume()
determinar qual fragmento está atualmente visível para o usuário.onResume()
é chamado quando o fragmento se tornou visível eonPause
quando para de ficar visível.Para habilitar esse comportamento no primeiro ViewPager, você deve passar o
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
parâmetro como o segundo argumento doFragmentPagerAdapter
construtor.fonte
Substituí o método Count do FragmentStatePagerAdapter associado e ele retornou a contagem total menos o número de páginas a serem ocultadas:
Portanto, se houver 3 fragmentos adicionados inicialmente ao ViewPager e apenas os 2 primeiros devem ser mostrados até que alguma condição seja atendida, substitua a contagem de páginas configurando TrimmedPages como 1 e ele deve mostrar apenas as duas primeiras páginas.
Isso funciona bem para as páginas no final, mas realmente não ajuda no começo ou no meio (embora haja várias maneiras de fazer isso).
fonte