Pregunta Cómo determinar cuándo Fragmento se vuelve visible en ViewPager


Problema: Fragmento onResume() en ViewPager se dispara antes de que el fragmento se vuelva realmente visible.

Por ejemplo, tengo 2 fragmentos con ViewPager y FragmentPagerAdapter. El segundo fragmento solo está disponible para usuarios autorizados y debo solicitar al usuario que inicie sesión cuando el fragmento se vuelva visible (mediante un cuadro de diálogo de alerta).

Pero el 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 se vuelva visible. Es por eso que estoy tratando de encontrar un evento que se dispara cuando el segundo fragmento se vuelve visible para mostrar un diálogo en el momento adecuado.

¿Cómo puede hacerse esto?


628
2018-04-05 07:58


origen


Respuestas:


ACTUALIZAR: Biblioteca de soporte de Android (rev 11) finalmente corrigió el problema de pista visible del usuario, ahora si usa la biblioteca de soporte para fragmentos, puede usar de forma segura getUserVisibleHint() o anular setUserVisibleHint() capturar los cambios según lo descrito por la respuesta de gorn.

ACTUALIZACIÓN 1 Aquí hay un pequeño problema con getUserVisibleHint(). Este valor es por defecto true.

// Hint provided by the app that this fragment is currently visible to the user.
boolean mUserVisibleHint = true;

Entonces puede haber un problema cuando intentas usarlo antes setUserVisibleHint() fue invocado Como solución, puede establecer el valor en onCreate método como este.

public void onCreate(@Nullable Bundle savedInstanceState) {
    setUserVisibleHint(false);

La respuesta obsoleta:

En la mayoría de los casos de uso, ViewPager solo muestra una página a la vez, pero los fragmentos precacheados también se ponen en estado "visible" (realmente invisible) si está utilizando FragmentStatePagerAdapter en Android Support Library pre-r11.

Anulo:

public class MyFragment extends Fragment {
    @Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {
            // ...
        }
    }
   // ...
}

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 ubicar sus elementos de menú junto con los elementos de la actividad principal.


472
2017-09-21 02:56



Cómo determinar cuándo Fragmento se vuelve visible en ViewPager

Puede hacer lo siguiente anulando setUserVisibleHint en tus Fragment:

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        }
        else {
        }
    }
}

519
2018-06-17 23:42



Esto parece restaurar la normalidad onResume() comportamiento que esperarías Funciona bien al presionar 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

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
        //Only manually call onResume if fragment is already visible
        //Otherwise allow natural fragment lifecycle to call onResume
        onResume();
    }
}

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

    //INSERT CUSTOM CODE HERE
}

105
2017-08-03 03:02



Aquí hay otra forma de usar onPageChangeListener:

  ViewPager pager = (ViewPager) findByViewId(R.id.viewpager);
  FragmentPagerAdapter adapter = new FragmentPageAdapter(getFragmentManager);
  pager.setAdapter(adapter);
  pager.setOnPageChangeListener(new OnPageChangeListener() {

  public void onPageSelected(int pageNumber) {
    // Just define a callback method in your fragment and call it like this! 
    adapter.getItem(pageNumber).imVisible();

  }

  public void onPageScrolled(int arg0, float arg1, int arg2) {
    // TODO Auto-generated method stub

  }

  public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub

  }
});

54
2017-08-03 14:41



setUserVisibleHint() se llama a veces antes de  onCreateView() y a veces después de lo cual causa problemas.

Para superar esto, debe verificar isResumed() también adentro setUserVisibleHint() método. Pero en este caso me di cuenta setUserVisibleHint() se llama solamente si el fragmento se reanuda y es visible, NO cuando se creó.

Entonces, si quieres actualizar algo cuando Fragment es visible, ponga su función de actualización tanto en onCreate() y setUserVisibleHint():

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

ACTUALIZAR: Todavía me di cuenta myUIUpdate() se llama dos veces a 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, también se crea la segunda pestaña, incluso si no está visible y myUIUpdate() se llama. Luego, cuando pases a la segunda pestaña, myUIUpdate() de if (visible && isResumed()) se llama y como resultado,myUIUpdate() puede ser llamado dos veces en un segundo.

El otro problema es !visible en setUserVisibleHint se llama tanto 1) cuando sale de la pantalla de fragmento como 2) antes de que se cree, cuando cambia a la pantalla de fragmento por primera vez.

Solución: 

private boolean fragmentResume=false;
private boolean fragmentVisible=false;
private boolean fragmentOnCreated=false;
...

@Override
public View onCreateView(...){
    ...
    //Initialize variables
    if (!fragmentResume && fragmentVisible){   //only when first time fragment is created
        myUIUpdate();
    }
    ...        
}

@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){   // only at fragment screen is resumed
        fragmentResume=true;
        fragmentVisible=false;
        fragmentOnCreated=true;
        myUIUpdate();
    }else  if (visible){        // only at fragment onCreated
        fragmentResume=false;
        fragmentVisible=true;
        fragmentOnCreated=true;
    }
    else if(!visible && fragmentOnCreated){// only when you go out of fragment screen
        fragmentVisible=false;
        fragmentResume=false;
    }
}

Explicación: 

fragmentResume,fragmentVisible: Se asegura myUIUpdate() en onCreateView() se llama solo cuando se crea el fragmento y es visible, no en el currículum. También resuelve el problema cuando estás en la 1ª pestaña, se crea la 2ª pestaña, incluso si no está visible. Esto resuelve eso y comprueba si la pantalla de fragmentos está visible cuando onCreate.

fragmentOnCreated: Se asegura de que el fragmento no sea visible y no se invoque cuando crea fragmentos por primera vez. Así que ahora esta cláusula if solo se llama cuando sales del fragmento.

Actualizar Puedes poner todo este código en BaseFragment código Me gusta esto y reemplazar el método.


50
2018-04-14 07:27



package com.example.com.ui.fragment;


import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.com.R;

public class SubscribeFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
        return view;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) {
            // called here
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

22
2018-01-06 13:54



Anular setPrimaryItem() en el FragmentPagerAdapter subclase. Yo uso este método, y funciona bien.

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    // This is what calls setMenuVisibility() on the fragments
    super.setPrimaryItem(container, position, object);

    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;
        fragment.doTheThingYouNeedToDoOnBecomingVisible();
    }
}

14
2018-06-19 18:34



Anular Fragment.onHiddenChanged() para eso.

public void onHiddenChanged(boolean hidden)

Llamado cuando el estado oculto (según lo devuelto por isHidden()) del fragmento ha cambiado. Los fragmentos comienzan no ocultos; esto se llamará siempre que el fragmento cambie de estado a partir de eso.

Parámetros
hidden - boolean: Verdadero si el fragmento está ahora oculto, falso si no está visible.


9
2017-09-09 12:04