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:
- No se puede obtener gridView en el elemento de escucha de clics
- Eclipse crea automáticamente el diseño del fragmento, ¿cómo puedo desactivarlo?
- Ejecutar código justo después de que un fragmento se vuelve visible por primera vez
- Barra de Acción Sherlock SearchView no se expande al hacer clic
- Reemplazar ListFragment con fragmento dentro de ViewPager con pestañas
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); } }
- Honeycomb Gmail Como Aplicación
- Android y RoboGuice - Inyectar vistas en Fragmento?
- Android: Viewpager y FragmentStatePageAdapter
- Cómo borrar argumentos en Fragmento?
- OnCreateOptionsMenu no se llama a FragmentActivity cuando se ejecuta en la versión de teléfono
- Android - ¿En qué hilo se ejecutan los fragmentos?
- Inicialización del reproductor de YouTube en Fragmento
- Selecciona la imagen de la galería que no funciona en Fragment Class en Android
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:
- Hacer que
Static
viewPager instancia en la actividad y el uso donde queramos - 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,
- 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 deviewPager
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.
- Intellij 13 Auto doc pop-up en la solución mouseover ya no funciona
- Este diseño de RelativeLayout o su padre LinearLayout es inútil