Ciclo de vida del fragmento: ¿a qué método se llama para mostrar / ocultar?

99

Estoy usando el siguiente método para cambiar entre Fragmentos (en mi NavigationDrawer) mostrándolos / ocultándolos.

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

Lo que no tengo claro es qué método del ciclo de vida de Fragmentos se llama cuando lo muestro u oculto. (dado que no hay un método como onShow () o onHide (), no estoy muy seguro de qué usar). Quiero realizar acciones específicas al mostrar y ocultar un determinado Fragmento.

Philipp Jahoda
fuente
cuando llama a Fragment.show () , en algún momento más tarde, el fragmento se activa onCreate(), seguido de onCreateDialog(), seguido deonCreateView()
Alguien en algún lugar

Respuestas:

122

Similar al ciclo de vida de la actividad, Android llama a onStart () cuando el fragmento se vuelve visible. onStop()normalmente se llama cuando el fragmento se vuelve invisible, pero también se puede llamar más adelante en el tiempo.

Dependiendo de su diseño, Android puede llamar onStart()incluso, cuando su Fragmento aún no está visible, pero pertenece a un contenedor principal visible. Por ejemplo, esto es válido para lo android.support.v4.view.ViewPagerque requiere que anule el Fragment.setUserVisibleHint()método. En cualquier caso, si necesita registrar / anular el registro de BroadcastReceivers u otros oyentes, puede usar los métodos onStart()y de forma segura onStop()porque siempre se llamarán.

Nota: Algunos contenedores de fragmentos pueden mantener iniciados los fragmentos invisibles. Para manejar esta situación, puede anular Fragment.onHiddenChanged(boolean hidden). Según la documentación , un fragmento debe estar tanto iniciado como visible (no oculto) para que sea visible para el usuario.

Actualización: si lo usa android.support.v4.widget.DrawerLayout, un fragmento debajo del cajón permanece encendido y visible incluso cuando el cajón está abierto. En este caso, debe usar DrawerLayout.setDrawerListener()y escuchar onDrawerClosed()y onDrawerOpened()devoluciones de llamada.

sergej shafarenka
fuente
14
onStopy onPauseno se llaman cuando un fragmento se vuelve invisible mediante una transacción. Sin embargo, onHiddenChangedse llama como sugiere la respuesta s1rius
Yoann Hercouet
Esto no funciona en NavigationDrawer. onHiddenChanged no se llama en la biblioteca de soporte v4 / v11. onStart y onResume también se llamarán no siempre, cuando se abre el diseño del cajón.
drdrej
@drdrej El problema es que el cajón no oculta el fragmento de abajo por completo. Si usa DrawerLayout de la biblioteca de soporte, necesita usar DrawerListener.
sergej shafarenka
69

Yo @Anulo este método y resuelvo mi problema:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}
s1rius
fuente
1
Intenté no resolverlo, pero el uso setUserVisibleHintcomo se muestra en stackoverflow.com/a/18375436/1815624 funciona
CrandellWS
36

por supuesto, puede @Override el siguiente método para hacerlo:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }
Biraj Zalavadia
fuente
Y uno puede saber fácilmente si el fragmento es visible para el usuario o no llamandogetUserVisibleHint()
ARiF
2
setUserVisibleHint funciona con el paginador de vistas pero no con el contenedor de fragmentos normal.
MikeL
Gracias, esto resuelve mi problema :)
RAJESH KUMAR ARUMUGAM
Esto funcionó para mí en ViewPager. onHiddenChanged no funcionó.
live-love
¡Resolvió mi problema!
Jad Chahine
3

Fragmento en el comportamiento del localizador de vista es diferente con el contenedor de fragmentos normal.

Prueba 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
fuente
2

Prueba 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
fuente
2

Puede usar 'onCreateView' (o 'onActivityCreated') y 'onHiddenChanged'. Use 'onCreateView' para la primera presentación y use 'onHiddenChanged' para más tarde. 'setMenuVisibility' no se llama en el control de transacciones.

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

@Override
public void onHiddenChanged(boolean hidden) {
    if (!hidden) {
        // fragment will show 
    }
    else {
        // fragment will hide
    }
}
hoi
fuente
onHiddenChanged () no se llama con mi fragmento
matdev
1

Solo prueba esto en tu 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;
    }
}

Y crea este código en onCreateView () :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}
Junco
fuente
isVisibleToUser && getView() != nullfuncionó perfecto para mí!
bobby
1

Otra forma de llamar al método de fragmento cuando el fragmento es visible y usa viewpager en actividad.

// primero que nada creas una interfaz

public interface ShowFragmentVisible{
      public void showFragment();}

// Después de eso, esta interfaz se implementa dentro de Fragment así

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

// Ahora va su actividad, luego crea un objeto de interfaz y llama adentro cuando 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
fuente
0

setUserVisibleHintllamar antes onCreateView. y no puede actualizar ninguna Vista dentro de setUserVisibleHint que uso

public void setMenuVisibility(final boolean visible)

para visibilidad y onHiddenChanged () no llamó por primera vez . llama cuando cambia el estado oculto. porque a fragment is visible by default. Para lograr este método por primera vez, debe llamar y mFragmentTransaction.hide(oldFragment)luego funcionará

Nota

si desea usar la sugerencia setUserVisible y actualizar la vista Use este método

AndroidGeek
fuente
0

Por supuesto, puede anular setUserVisibleHinto, setMenuVisibilitypero si necesita acceder a Contexto Activity, ¡serán nulos allí! Hay otro metodoonStart que siempre tiene el contexto disponible a mano, pero solo se llamará una vez después de la creación del fragmento y si comienza a moverse entre sus fragmentos en un buscapersonas, verá que no se llamará en la segunda vista y luego .

Entonces ... ¿qué hacer ahora?

La solución es bastante fácil, utilícela onStartpara la primera visita y setMenuVisibilitypara las posteriores. Su código probablemente se verá como a continuación:

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

De esta forma Contextsiempre estará disponible para el doSth()método.

AmiNadimi
fuente
0

¡Solo esto funcionó para mí! y setUserVisibleHint(...)ahora está en desuso (adjunté documentos al final), lo que significa que algunas otras respuestas están en desuso ;-)

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

Probado y también funciona NaviagationDrawer, isMenuVisible()siempre volverá true(y onResume()parece suficiente, pero también queremos apoyar ViewPager).

setUserVisibleHintes obsoleto. Si se anula este método, el comportamiento implementado al pasar truedebe cambiarse a Fragment.onResume()y el comportamiento implementado al pasar falsea Fragment.onPause().

Top Master
fuente