Comprobar fragmento está visible o no en android?

Sé que hay muchas preguntas similares en StackOverflow, pero mi pregunta es poco diferente.

He jerarquizado jerarquía de Fragmentos como en debajo de la estructura:

Activity | | AFragment | (ViewPager) | | | | BFragment BFragment ..... | (ViewPager) | | | | CFragment CFragment ... | (ViewPager) | | | | DFragment DFragment ... 

Ahora quiero saber que si DFragment se muestra al usuario o no?

He intentado mucha solución de StackOverflow pero no pude conseguir el éxito.

Lo que intenté es:

Intenté setUserVisibleHint() pero devuelve true para el DFragment múltiple en jerarquía antedicha que es una causa de ViewPager

También intenté de estos acoplamientos: link1 , link2 , link3 y así sucesivamente … pero no conseguí la solución real.

Esperando ayuda. Gracias.

ACTUALIZAR

Clase del Adaptador

 class ViewPagerAdapter extends FragmentPagerAdapter { private final List<Fragment> mFragmentList = new ArrayList<>(); private final List<String> mFragmentTitleList = new ArrayList<>(); public ViewPagerAdapter(FragmentManager manager) { super(manager); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } public void addFragment(Fragment fragment, String title) { mFragmentList.add(fragment); mFragmentTitleList.add(title); } @Override public CharSequence getPageTitle(int position) { return mFragmentTitleList.get(position); } } 

Puede comprobar si la View que el fragmento inflado es visible en la pantalla del dispositivo:

 Fragment fragment = ... // retrieve from `ViewPager`'s adapter. View fragmentRootView = fragment.getView(); Rect rect = new Rect(); if (null != fragmentRootView && fragmentRootView.getGlobalVisibleRect(rect)) { // fragment is visible } else { // fragment is not visible } 

getGlobalVisibleRect() devolverá true si parte de la vista es visible en el nivel raíz.

prueba esto

 @Override public void setMenuVisibility(final boolean visible) { super.setMenuVisibility(visible); if (visible) { } else { } } 

Puede override setUserVisibleHint() en cada fragmento donde desea comprobar si está visible o no con un indicador adicional. Para un ejemplo

 boolean isVisited = false; @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser && !isVisited ) { isVisited = true; } else if(isVisited) { // this fragment is already in front of user } } 

Estaba teniendo un problema similar. Una vez que era necesario cargar datos del servidor para fragment sólo cuando estaba en frente del usuario. Lo resolví como antes.

Espero que te ayude también.

Prueba esto.

El isVisible() agrega y capa adicional de comprobación de visibilidad.

  ViewPager viewPager=(ViewPager)findViewById(R.id.view_pager); final Fragment[] fragments={new DFragment(),new MyFragment()}; //add all the other fragment objects present in the view pager...... viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if(fragments[position].isVisible()){ //Cool stuff to do. } } @Override public void onPageScrollStateChanged(int state) { } }); 

Por lo que he probado, creo que esto funcionará. Por favor, inténtalo y hazme saber. Haga algo como esto en su actividad.


 public boolean isFragmentVisible(SwipeAdapter swipeAdapter) { SwipeAdapter swipeAdapterA = fragmentA.getViewPagerAdapter(); BFragment bFragment = (BFragment) swipeAdapterA.getFragment(0); if (bFragment != null) { SwipeAdapter swipeAdapterB = bFragment.getViewPagerAdapter(); CFragment cFragment = (CFragment) swipeAdapterA.getFragment(0); if (cFragment != null) { SwipeAdapter swipeAdapterC = cFragment.getViewPagerAdapter(); DFragment dFragment = (DFragment) swipeAdapterA.getFragment(0); if (dFragment != null) { return dFragment.isFragmentVisible(); } } } return false; } 

Utilice esta clase como su adaptador de viewpager

  class SwipeAdapter extends FragmentPagerAdapter { private Map<Integer, String> mFragmentTags; private FragmentManager mFragmentManager; private String mPagetile[]; public SwipeAdapter(FragmentManager fm, Context context) { super(fm); mPagetile = context.getResources().getStringArray(R.array.pageTitle); mFragmentManager = fm; mFragmentTags = new HashMap<>(); } @Override public Fragment getItem(int position) { switch (position) { case 0: return new "Your_fragment"; default: break; } return null; } @Override public Object instantiateItem(ViewGroup container, int position) { Object obj = super.instantiateItem(container, position); if (obj instanceof Fragment) { Fragment f = (Fragment) obj; String tag = f.getTag(); mFragmentTags.put(position, tag); } return obj; } public Fragment getFragment(int position) { String tag = mFragmentTags.get(position); if (tag == null) return null; return mFragmentManager.findFragmentByTag(tag); } @Override public CharSequence getPageTitle(int position) { return mPagetile[position]; } @Override public int getCount() { return "Number of fragments"; } } 

Ahora en tu DFragment haz esto

  boolean isVisible=false; @Override public void setMenuVisibility(boolean menuVisible) { super.setMenuVisibility(menuVisible); isVisible=menuVisible; } public boolean isFragmentVisible(){ return isVisible; } 

Déjeme saber si funcionó si no me deja saber la razón.

Podemos localizar fácilmente el fragmento que ahora está visible usando el método mViewPager.getCurrentItem() . Este método da el número de valor int del cual podemos encontrar el fragmento actual.

– Para acceder y obtener este resultado de método tenemos dos opciones:

  1. Hacer que Static viewPager instancia en la actividad y el uso donde queramos
  2. Vuelve a hacer la instancia de viewPager en fragmento ( findViewById() )

Y utilizando uno de los dos métodos getCurrentItem() en el fragmento para encontrar qué fragmento es visible ahora.

Por ejemplo,

  1. En MainActivity (actividad que se utiliza para ViewPager) define

public static ViewPager mViewPager;

  • En Fragmento, MainActivity.mViewPager.getCurrentItem() para obtener el fragmento actual

También, el método que muestra qué fragmento es visible:

 public void whichIsVisible() { String msg = ""; int curFragNo = MainActivity.mViewPager.getCurrentItem(); switch (curFragNo) { case 0: msg = "AFragment is visible."; break; case 1: msg = "BFragment is visible."; break; case 2: msg = "CFragment is visible."; break; case 3: msg = "DFragment is visible."; break; } Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } 

(2) Para uso no estático,

  • viewPager instancia de viewPager en fragmento por debajo de código,

viewPager=(ViewPager) view.getRootView().findViewById(R.id.container);

y entonces

viewPager.getCurrentItem() para obtener el índice y encontrar el fragmento visible actual según el uso.

La más simple puede ser. En onCreate de su DF fragment almacene un boolean en las preferences . Es decir, Key = is_fragment_visible_to_user . Y cambiarlo a true . Y en onStop o onDestroy (lo que llena su requisito) cambie, su valor es false . Con esto, puede comprobarlo fácilmente accediendo al valor de preferencias. En el caso de varias instancias, puede almacenar la etiqueta con la otra clave.

Cuando tuve un problema similar, lo solucioné usando este método hacky 'bajo el capó' como

Dentro de su FragmentPagerAdapter (s) agregar esta función.

 public Fragment getActiveFragment(ViewPager container, int position) { String name = makeFragmentName(container.getId(), position); return fm.findFragmentByTag(name); } private static String makeFragmentName(int viewId, int index) { return "android:switcher:" + viewId + ":" + index; } 

No es la solución más graciosa, pero siempre y cuando funcione

PRECAUCIÓN

Este es un método privado interno a ViewPager que puede cambiar en cualquier momento o para cualquier versión del sistema operativo.

Aunque el pasado por tanto tiempo, pero todavía quiero dar mi programa, porque he encontrado que obtener estado visible de Fragmento no es fácil. Basado en su petición, usted necesita resolver estas tres preguntas:

  • Cómo utilizar FragmentPagerAdapter o FragmentStatePagerAdapter
  • Cómo determinar el estado visible del fragmento
  • Cómo manejar cuando el Fragmento está anidado

En primer lugar, definí un adaptador de base que me ayude a obtener el fragmento en ViewPager.If posición de su fragmento y el tipo es cambiable en ViewPager, debe utilizar public int getItemPosition(Object object) method public Fragment getItem(int position) y el public int getItemPosition(Object object) method public Fragment getItem(int position) para obtener La posición correcta.

 /** * Created by Kilnn on 2017/7/12. * A abstract FragmentStatePagerAdapter which hold the fragment reference. */ public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter { private SparseArray<WeakReference<Fragment>> registeredFragments = new SparseArray<>(); public SmartFragmentStatePagerAdapter(FragmentManager fm) { super(fm); } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); registeredFragments.put(position, new WeakReference<>(fragment)); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { registeredFragments.remove(position); super.destroyItem(container, position, object); } public Fragment getRegisteredFragment(int position) { WeakReference<Fragment> reference = registeredFragments.get(position); return reference != null ? reference.get() : null; } } 

A continuación, defino un Fragmento de base para manejar el estado visible. Pero hay una pequeña falla es que debe especificar el mismo tipo de conmutador para un conjunto de fragmento.

 import android.support.annotation.IntDef; import android.support.v4.app.Fragment; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Created by Kilnn on 2017/7/12. * A smart fragment know itself's visible state. */ public abstract class SmartFragment extends Fragment { private boolean isFragmentVisible; @Override public void onResume() { super.onResume(); int switchType = getSwitchType(); if (switchType == ATTACH_DETACH) { notifyOnFragmentVisible(); } else if (switchType == SHOW_HIDE) { if (!isHidden()) { notifyOnFragmentVisible(); } } else if (switchType == VIEW_PAGER) { //If the parent fragment exist and hidden when activity destroy, //when the activity restore, The parent Fragment will be restore to hidden state. //And the sub Fragment which in ViewPager is also be restored, and the onResumed() method will callback. //And The sub Fragment's getUserVisibleHint() method will return true if it is in active position. //So we need to judge the parent Fragment visible state. if (getUserVisibleHint() && isParentFragmentVisible()) { notifyOnFragmentVisible(); } } } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); int switchType = getSwitchType(); if (switchType == VIEW_PAGER) { if (isVisibleToUser) { //If ViewPager in ViewPager , the sub ViewPager will call setUserVisibleHint before onResume if (isResumed()) { notifyOnFragmentVisible(); } } else { notifyOnFragmentInvisible(); } } } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); int switchType = getSwitchType(); if (switchType == SHOW_HIDE) { if (hidden) { notifyOnFragmentInvisible(); } else { //Just judge for safe if (isResumed()) { notifyOnFragmentVisible(); } } } } @Override public void onPause() { super.onPause(); notifyOnFragmentInvisible(); } private boolean isParentFragmentVisible() { Fragment parent = getParentFragment(); if (parent == null) return true; if (parent instanceof SmartFragment) { return ((SmartFragment) parent).isFragmentVisible(); } else { //TODO May be can't get the correct visible state if parent Fragment is not SmartFragment return parent.isVisible(); } } public boolean isFragmentVisible() { // Don't judge the state of the parent fragment, // because if the parent fragment visible state changes, // you must take the initiative to change the state of the sub fragment // return isFragmentVisible && isParentFragmentVisible(); return isFragmentVisible; } public void notifyOnFragmentVisible() { if (!isFragmentVisible) { onFragmentVisible(); isFragmentVisible = true; } } public void notifyOnFragmentInvisible() { if (isFragmentVisible) { onFragmentInvisible(); isFragmentVisible = false; } } /** * If this method callback, the Fragment must be resumed. */ public void onFragmentVisible() { } /** * If this method callback, the Fragment maybe is resumed or in onPause(). */ public void onFragmentInvisible() { } /** * Fragments switch with attach/detach(replace) */ public static final int ATTACH_DETACH = 0; /** * Fragments switch with show/hide */ public static final int SHOW_HIDE = 1; /** * Fragments manage by view pager */ public static final int VIEW_PAGER = 2; @Retention(RetentionPolicy.SOURCE) @IntDef({ATTACH_DETACH, SHOW_HIDE, VIEW_PAGER}) public @interface SwitchType { } @SwitchType public abstract int getSwitchType(); } 

Por último, sume el estado visible del fragmento secundario en el fragmento padre si está anidado.

 public class ParentFragment extends SmartFragment{ .... @Override public void onFragmentVisible() { super.onFragmentVisible(); SmartFragment fragment = (SmartFragment) mAdapter.getRegisteredFragment(mViewPager.getCurrentItem()); if (fragment != null) { fragment.notifyOnFragmentVisible(); } } @Override public void onFragmentInvisible() { super.onFragmentInvisible(); SmartFragment fragment = (SmartFragment) mAdapter.getRegisteredFragment(mViewPager.getCurrentItem()); if (fragment != null) { fragment.notifyOnFragmentInvisible(); } } ... } 

Tengo prueba con adjuntar / separar, mostrar / ocultar, y tres capas ViewPager anidado. Funciona bien. Tal vez debería haber hecho más pruebas, pero para mí fue suficiente.

  • No se puede cambiar ID de contenedor de fragmento
  • Android Master / Detalle de flujo dentro de ViewPager
  • Tecla Atrás en Fragmento añadido mediante programación lleva a contenedor vacío
  • Android Fragment, Force View para liberar manualmente
  • Reemplazar un fragmento / ficha en un Viewpager
  • PopBackStack hace que llamar a oncreateView del fragmento una y otra vez
  • Android - FragmentTabHost me da "No se conoce ninguna pestaña para la etiqueta null"
  • Mis fragmentos en la pestaña viewpager no se actualizan
  • Comprobar fragmento se presenta en framelayout o no en android?
  • ¿Hay alguna alternativa a Fragmentos anidados?
  • Fragmento de actualización de ViewPager en el dispositivo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.