Ciclo de vida do fragmento - qual método é chamado para mostrar / ocultar?

99

Estou usando o seguinte método para alternar entre Fragments (em meu NavigationDrawer), mostrando / ocultando-os.

protected void showFragment(int container, Fragment fragment, String tag, String lastTag, boolean addToBackStack ) {

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if ( lastTag != null && !lastTag.equals("")) {
            Fragment lastFragment = fragmentManager.findFragmentByTag( lastTag );
            if ( lastFragment != null ) {
                transaction.hide( lastFragment );
            }
        }

        if ( fragment.isAdded() ) {
            transaction.show( fragment );
        }
        else {
            transaction.add( container, fragment, tag );
        }

        if ( addToBackStack ) {
            transaction.addToBackStack( tag );
        }

        transaction.commit();

        // set the active tag
        activeFragTag = tag;
    }

O que não estou certo é qual método do ciclo de vida do Fragments é chamado quando eu o mostro ou oculto? (uma vez que não há nenhum método como onShow () ou onHide (), não tenho certeza do que usar). Quero realizar ações específicas ao mostrar e ocultar um determinado fragmento.

Philipp Jahoda
fonte
quando você chama Fragment.show () , em algum momento depois, o fragmento é acionado onCreate(), seguido por onCreateDialog(), seguido poronCreateView()
Someone Somewhere

Respostas:

122

Semelhante ao ciclo de vida da atividade, o Android chama onStart () quando o fragmento se torna visível. onStop()normalmente é chamado quando o fragmento se torna invisível, mas também pode ser chamado posteriormente.

Dependendo de seu layout, o Android pode chamar onStart()even, quando seu Fragment ainda não está visível, mas pertence a um contêiner pai visível. Por exemplo, isso é válido para o android.support.v4.view.ViewPagerque requer que você substitua o Fragment.setUserVisibleHint()método. Em qualquer caso, se você precisar registrar / cancelar o registro de BroadcastReceivers ou outros ouvintes, você pode usar os métodos onStart()e com segurança onStop()porque eles serão sempre chamados.

Nota: Alguns contêineres de fragmentos podem manter fragmentos invisíveis iniciados. Para lidar com essa situação, você pode substituir Fragment.onHiddenChanged(boolean hidden). De acordo com a documentação , um fragmento deve ser iniciado e visível (não oculto) , para ser visível ao usuário.

Atualização: Se você usar android.support.v4.widget.DrawerLayout, um fragmento abaixo da gaveta permanece aberto e visível mesmo quando a gaveta está aberta. Nesse caso, você precisa usar DrawerLayout.setDrawerListener()e ouvir onDrawerClosed()e onDrawerOpened()callbacks.

Sergej Shafarenka
fonte
14
onStope onPausenão são chamados quando um fragmento se torna invisível por meio de uma transação. No entanto, onHiddenChangedé chamado como sugere resposta s1rius
Yoann Hercouet
Isso não funciona no NavigationDrawer. onHiddenChanged não é chamado na biblioteca de suporte v4 / v11. onStart e onResume também não serão chamados todas as vezes, quando o layout da gaveta for aberto.
drdrej
@drdrej O problema é que a gaveta não esconde o fragmento abaixo completamente. Se você usar DrawerLayout da biblioteca de suporte, será necessário usar DrawerListener.
sergej shafarenka
69

Eu @subro este método e resolvo meu problema:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}
s1rius
fonte
1
Tentou sem resolver, mas usando setUserVisibleHintconforme mostrado em stackoverflow.com/a/18375436/1815624 funciona
CrandellWS
36

é claro que você pode substituir o seguinte método para fazer isso:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }
Biraj Zalavadia
fonte
E pode-se saber facilmente se o fragmento está visível para o usuário ou não chamandogetUserVisibleHint()
ARiF 01/09/16
2
setUserVisibleHint funciona com o pager de visualização, mas não com o contêiner de fragmento regular.
MikeL
Obrigado, resolve o meu problema :)
RAJESH KUMAR ARUMUGAM
Isso funcionou para mim no ViewPager. onHiddenChanged não funcionou.
live-love de
Resolveu meu problema!
Jad Chahine de
3

O comportamento do fragmento no pager de visualização é diferente com o contêiner de fragmento regular.

Experimente este código:

    boolean mIsVisibleToUser;

    /**
     * is visible to user
     */
    public void show() {
        //do when show
    }

    /**
     * is invisible to user
     */
    public void hide() {
        //do when gone
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = true;
            show();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = false;
            hide();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isResumed()) {
            if (mIsVisibleToUser != isVisibleToUser) {
                mIsVisibleToUser = isVisibleToUser;
                if (isVisibleToUser) show();
                else hide();
            }
        }
    }

    public boolean isVisibleToUser() {
        return mIsVisibleToUser;
    }
Alan Yuan
fonte
2

Experimente este código:

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
         onResume();
    }
}

@Override
public void onResume()
{
    super.onResume();
    if (!getUserVisibleHint())
    {
        return;
    }

    //Add your code this section
}
Ahmad Aghazadeh
fonte
2

Você pode usar 'onCreateView' (ou 'onActivityCreated') e 'onHiddenChanged'. Use 'onCreateView' para o primeiro show e use 'onHiddenChanged' para depois. 'setMenuVisibility' não é chamado no controle de transação.

@Override
public View OnCreateView() {
   // fragment will show first
}

@Override
public void onHiddenChanged(boolean hidden) {
    if (!hidden) {
        // fragment will show 
    }
    else {
        // fragment will hide
    }
}
Hoi
fonte
onHiddenChanged () não é chamado com meu fragmento
matdev
1

Apenas tente isso em seu setUserVisibleHint ()

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser && getView() != null){
        isActive = true;
        init();
    }else if(isVisibleToUser && getView() == null){
        isActive = false;
    }else{
        isActive = true;
    }
}

E crie este código em onCreateView () :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}
junco
fonte
isVisibleToUser && getView() != nullfuncionou perfeito para mim!
bobby
1

Outra maneira de chamar o método de fragmento quando o fragmento está visível e você usa o viewpager na atividade.

// antes de mais nada, você cria uma interface

public interface ShowFragmentVisible{
      public void showFragment();}

// Depois disso, esta interface implementa dentro do Fragment assim

      public class MyFragment extends Fragment implements 
         ShowFragmentVisible {
            @Override
public void showFragment() {
}

// Agora vai sua Activity, então cria o objeto da interface e chama dentro quando addOnViewpagerListener

   ShowFragmentVisible showFragmentVisible;

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    if (fragment instanceof ShowFragmentVisible) {
        showFragmentVisible = (ShowFragmentVisible) fragment;
    }

}
     //your viewpager method
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            if (position==0){
                showFragmentVisible.showFragment();

           }

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });


this is another alternative,but its work for me successfully
Jatin Bansal
fonte
0

setUserVisibleHintligue antes onCreateView. e você não pode atualizar qualquer View dentro de setUserVisibleHint que eu uso

public void setMenuVisibility(final boolean visible)

para visibilidade e onHiddenChanged () não chamaram pela primeira vez . ele chama quando o estado oculto muda. porque um fragment is visible by default. Para atingir este método pela primeira vez, você deve chamar, mFragmentTransaction.hide(oldFragment)então ele funcionará

Nota

se você quiser usar a dica setUserVisible e atualizar o modo de exibição Use este método

Zar E Ahmer
fonte
0

Claro que você pode substituir setUserVisibleHintou, setMenuVisibilitymas se você precisar acessar Contextou Activity, eles serão nulos lá! Existe outro método onStartque sempre tem o contexto disponível, mas ele só será chamado uma vez na criação do fragmento e se você começar a se mover entre seus fragmentos em um pager verá que ele não será chamado na segunda visualização e depois .

Então o que fazer agora?

A solução é bastante fácil, use onStartna primeira visita e setMenuVisibilitynas posteriores. Seu código provavelmente será assim:

Classe de fragmento:

public class MyFragmentClass{
    private boolean isCurrentVisible = false;
...

@Override
public void onStart() {
    super.onStart();
    if (isCurrentVisible)
        doSth();
}

@Override
public void setMenuVisibility(boolean menuVisible){
    super.setMenuVisibility(menuVisible);
    this.isCurrentVisible = menuVisible;
    if(menuVisible && getContext() != null)
        doSth();
}

Desta forma, Contextestará sempre disponível para o doSth()método.

AmiNadimi
fonte
0

Só isso funcionou para mim !! e setUserVisibleHint(...)agora está obsoleto (anexei os documentos no final), o que significa que algumas outras respostas estão obsoletas ;-)

public class FragmentFirewall extends Fragment {
    /**
     * Required cause "setMenuVisibility(...)" is not guaranteed to be
     * called after "onResume()" and/or "onCreateView(...)" method.
     */
    protected void didVisibilityChange() {
        Activity activity = getActivity();
        if (isResumed() && isMenuVisible()) {
            // Once resumed and menu is visible, at last
            // our Fragment is really visible to user.
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        didVisibilityChange();
    }

    @Override
    public void setMenuVisibility(boolean visible) {
        super.setMenuVisibility(visible);
        didVisibilityChange();
    }
}

Testado e funciona NaviagationDrawerbem, isMenuVisible()sempre haverá retorno true(e onResume()parece suficiente, mas queremos apoiar ViewPagertambém).

setUserVisibleHintestá obsoleto. Se substituir este método, o comportamento implementado ao passar truedeve ser movido para Fragment.onResume()e o comportamento implementado ao passar falsedeve ser movido para Fragment.onPause().

Mestre superior
fonte