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.


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.


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
    }
}

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
        }
    }

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;
    }

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
}

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
    }
}

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();
  }
}

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

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


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.


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().

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.