Recuperar un fragmento de un ViewPager
Estoy usando un ViewPager
junto con un FragmentStatePagerAdapter
para alojar tres fragmentos diferentes:
- [Fragmento1]
- [Fragmento2]
- [Fragmento3]
Cuando quiero obtener Fragment1
desde ViewPager
en la FragmentActivity
.
- TabLayout con ViewPager no funciona dentro de fragmento Android
- ListView con Viewpager como un encabezado dentro de TabPageIndicator
- PagerSlidingTabStrip: Alineación de las pestañas de ViewPager a la derecha
- ¿Cómo pasar argumentos de fragmentos mientras se utiliza un paginador de vista con diferentes fragmentos / layouts?
- ¿Cómo crear ViewPager de carrusel?
¿Cuál es el problema y cómo lo soluciono?
- NestedScrollView contiene contenido menor que la altura de la pantalla Desplaza en CoordinatorLayout
- Cómo hacer que mi viewpager pase de derecha a izquierda
- Android Definir texto de TextView en fragmento que está en FragmentPagerAdapter
- Mostrar video de Youtube en viewpager
- Sincronizar dos ViewPagers con OnPageChangeListener
- Determinar el fragmento visible en ViewPager
- Cómo deslizar las pestañas dentro de un fragmento de cajón de navegación
- ¿Cómo escribir el método onClick en el viewpager?
La respuesta principal se basa en un nombre generado por el marco. Si eso cambia, entonces ya no funcionará.
¿Qué pasa con esta solución, reemplazando instantiateItem()
y destroyItem()
de su Fragment(State)PagerAdapter
:
public class MyPagerAdapter extends FragmentStatePagerAdapter { SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>(); public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return ...; } @Override public Fragment getItem(int position) { return MyFragment.newInstance(...); } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); registeredFragments.put(position, 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) { return registeredFragments.get(position); } }
Esto parece funcionar para mí cuando se trata de fragmentos que están disponibles. Los fragmentos que aún no han sido instanciados devolverán null al llamar a getRegisteredFragment
. Pero he estado usando esto principalmente para obtener el Fragment
actual de ViewPager
: adapater.getRegisteredFragment(viewPager.getCurrentItem())
y esto no devolverá null
.
No tengo conocimiento de otros inconvenientes de esta solución. Si hay alguno, me gustaría saberlo.
Para agarrar fragmentos de un ViewPager hay un montón de respuestas aquí y en otros temas relacionados SO / blogs. Todo el mundo que he visto está roto, y por lo general parecen caer en uno de los dos tipos que se enumeran a continuación. Hay algunas otras soluciones válidas si sólo quieres agarrar el fragmento actual, como esta otra respuesta en este hilo.
Si utiliza FragmentPagerAdapter
consulte a continuación. Si utiliza FragmentStatePagerAdapter
vale la pena mirar esto . Los índices de agarre que no son los actuales en un FragmentStateAdapter no son tan útiles como por la naturaleza de que estos serán completamente destruidos salió de la vista / fuera de los límites de offScreenLimit.
LOS CAMINOS INFANTILES
Mal: Mantenga su propia lista interna de fragmentos, agregada a cuando se llama FragmentPagerAdapter.getItem()
- Usando generalmente un
SparseArray
o unMap
- No es uno de los muchos ejemplos que he visto cuentas de eventos de ciclo de vida por lo que esta solución es frágil. Como
getItem
sólo se llama la primera vez que una página se desplaza a (o se obtiene si suViewPager.setOffscreenPageLimit(x)
> 0) en elViewPager
, si laActivity
acogida /Fragment
es matado o reiniciado entonces elSpaseArray
interno será aniquilado cuando Se vuelve a crear la FragmentPagerActivity personalizada, pero detrás de las escenas se recrearán los fragmentos internos de ViewPagers ygetItem
segetItem
agetItem
para ninguno de los índices, por lo que la capacidad de obtener un fragmento del índice se perderá para siempre. Puedes dar cuenta de esto ahorrando y restaurando estas referencias de fragmentos a través deFragmentManager.getFragment()
yputFragment
pero esto comienza a ser IMHO desordenado.
Wrong: Construya su propio id de etiqueta que coincida con lo que se utiliza bajo el capó en FragmentPagerAdapter
y utilícelo para recuperar la página Fragments del FragmentManager
- Esto es mejor en la medida en que se ocupa del problema de las referencias de fragmentos perdidos en la primera solución de matriz interna, pero como se ha señalado correctamente en las respuestas anteriores y en otras partes de la red, se siente hacky como un método privado interno de
ViewPager
que Podría cambiar en cualquier momento o para cualquier versión del sistema operativo.
El método que se recrea para esta solución es
private static String makeFragmentName(int viewId, long id) { return "android:switcher:" + viewId + ":" + id; }
HAPPY PATH: ViewPager.instantiateItem()
Un enfoque similar a getItem()
anterior, pero sin romper el ciclo de vida es a esto es conectar en instantiateItem()
lugar de getItem()
como el primero se llamará cada vez que se crea el índice / se accede. Ver esta respuesta
UN CAMINO FELIZ: Construya su propio FragmentViewPager
Construya su propia clase FragmentViewPager
desde el origen de la última lib de soporte y cambie el método utilizado internamente para generar las etiquetas de fragmento. Puede reemplazarlo por el siguiente. Esto tiene la ventaja de que usted sabe que la creación de la etiqueta nunca cambiará y su no confiar en un api / método privado, que siempre es peligroso.
/** * @param containerViewId the ViewPager this adapter is being supplied to * @param id pass in getItemId(position) as this is whats used internally in this class * @return the tag used for this pages fragment */ public static String makeFragmentName(int containerViewId, long id) { return "android:switcher:" + containerViewId + ":" + id; }
A continuación, como dice el doc, cuando quiera agarrar un fragmento usado para un índice, simplemente llame a algo como este método (que puede poner en el FragmentPagerAdapter
personalizado o en una subclase) teniendo en cuenta que el resultado puede ser nulo si getItem aún no ha sido llamado Para esa página, es decir, no se ha creado todavía.
/** * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on * the current positions fragment. */ public @Nullable Fragment getFragmentForPosition(int position) { String tag = makeFragmentName(mViewPager.getId(), getItemId(position)); Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag); return fragment; }
Esta es una solución simple y resuelve los problemas en las otras dos soluciones que se encuentran por todas partes en la web
Agregue los siguientes métodos a su FragmentPagerAdapter:
public Fragment getActiveFragment(ViewPager container, int position) { String name = makeFragmentName(container.getId(), position); return mFragmentManager.findFragmentByTag(name); } private static String makeFragmentName(int viewId, int index) { return "android:switcher:" + viewId + ":" + index; }
GetActiveFragment (0) tiene que funcionar.
Aquí está la solución implementada en ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Si algo falla, verá un buen registro de fallos.
Otra solución sencilla:
public class MyPagerAdapter extends FragmentPagerAdapter { private Fragment mCurrentFragment; public Fragment getCurrentFragment() { return mCurrentFragment; } //... @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { if (getCurrentFragment() != object) { mCurrentFragment = ((Fragment) object); } super.setPrimaryItem(container, position, object); } }
Sé que esto tiene algunas respuestas, pero tal vez esto ayudará a alguien. He utilizado una solución relativamente simple cuando necesitaba obtener un Fragment
de mi ViewPager
. En tu Activity
o Fragment
sostiene ViewPager
, puedes usar este código para recorrer cada Fragment
que contiene.
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter(); for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) { Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i); if(viewPagerFragment != null) { // Do something with your Fragment // Check viewPagerFragment.isResumed() if you intend on interacting with any views. } }
-
Si conoce la posición de su
Fragment
enViewPager
, puede llamar agetItem(knownPosition)
. -
Si no conoce la posición de su
Fragment
enViewPager
, puede hacer que sus hijosFragments
implementen una interfaz con un método comogetUniqueId()
y utilícelos para diferenciarlos. O puede recorrer todos losFragments
y comprobar el tipo de clase, comoif(viewPagerFragment instanceof FragmentClassYouWant)
!!! EDITAR !!!
He descubierto que getItem
sólo es llamado por un FragmentPagerAdapter
cuando cada Fragment
necesita ser creado la primera vez , después de eso, parece que los Fragments
se reciclan con el FragmentManager
. De esta manera, muchas implementaciones de FragmentPagerAdapter
crean nuevos Fragment
en getItem
. Usando mi método anterior, esto significa que crearemos Fragment
nuevos cada vez que getItem
se llame mientras pasamos por todos los elementos en el FragmentPagerAdapter
. Debido a esto, he encontrado un mejor enfoque, utilizando el FragmentManager
para obtener cada Fragment
lugar (utilizando la respuesta aceptada). Esta es una solución más completa, y ha funcionado bien para mí.
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter(); for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) { String name = makeFragmentName(mViewPager.getId(), i); Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name); // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name); if(viewPagerFragment != null) { // Do something with your Fragment if (viewPagerFragment.isResumed()) { // Interact with any views/data that must be alive } else { // Flag something for update later, when this viewPagerFragment // returns to onResume } } }
Y necesitará este método.
private static String makeFragmentName(int viewId, int position) { return "android:switcher:" + viewId + ":" + position; }
Para mi caso, ninguna de las soluciones anteriores funcionó.
Sin embargo, desde que estoy usando el Fragmento de Hijo en un Fragmento, se utilizó lo siguiente:
Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
Esto sólo funcionará si los fragmentos en el Administrador corresponden al elemento viewpager.
Esto se basa en la respuesta de Steven arriba. Esto devolverá la instancia real del fragmento que ya está unido a la actividad padre.
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter(); for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) { Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i); if(viewPagerFragment != null && viewPagerFragment.isAdded()) { if (viewPagerFragment instanceof FragmentOne){ FragmentOne oneFragment = (FragmentOne) viewPagerFragment; if (oneFragment != null){ oneFragment.update(); // your custom method } } else if (viewPagerFragment instanceof FragmentTwo){ FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment; if (twoFragment != null){ twoFragment.update(); // your custom method } } } }
No pude encontrar una manera sencilla y limpia de hacer esto. Sin embargo, el widget ViewPager es sólo otro ViewGroup, que alberga sus fragmentos. ViewPager tiene estos fragmentos como niños inmediatos. Por lo tanto, podría simplemente iterar sobre ellos (usando .getChildCount () y .getChildAt ()), y ver si la instancia de fragmento que está buscando está cargada en ViewPager y obtener una referencia a ella. Por ejemplo, podría utilizar algún campo de ID único estático para distinguir los fragmentos.
Tenga en cuenta que el ViewPager puede no haber cargado el fragmento que está buscando, ya que es un contenedor de virtualización como ListView.
FragmentPagerAdapter es la fábrica de los fragmentos. Para encontrar un fragmento basado en su posición si todavía en la memoria utilice esto:
public Fragment findFragmentByPosition(int position) { FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter(); return getSupportFragmentManager().findFragmentByTag( "android:switcher:" + getViewPager().getId() + ":" + fragmentPagerAdapter.getItemId(position)); }
Código de ejemplo para api de soporte v4.
Lo manejé primero haciendo una lista de todos los fragmentos ( List<Fragment> fragments;
) que iba a usar y luego los agregaba al buscapersonas haciendo más fácil manejar el fragmento visto actualmente.
Asi que:
@Override onCreate(){ //initialise the list of fragments fragments = new Vector<Fragment>(); //fill up the list with out fragments fragments.add(Fragment.instantiate(this, MainFragment.class.getName())); fragments.add(Fragment.instantiate(this, MenuFragment.class.getName())); fragments.add(Fragment.instantiate(this, StoresFragment.class.getName())); fragments.add(Fragment.instantiate(this, AboutFragment.class.getName())); fragments.add(Fragment.instantiate(this, ContactFragment.class.getName())); //Set up the pager pager = (ViewPager)findViewById(R.id.pager); pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments)); pager.setOffscreenPageLimit(4); }
Así que esto puede llamarse:
public Fragment getFragment(ViewPager pager){ Fragment theFragment = fragments.get(pager.getCurrentItem()); return theFragment; }
Así que entonces podría chuck en una declaración if que sólo se ejecutaría si estaba en el fragmento correcto
Fragment tempFragment = getFragment(); if(tempFragment == MyFragmentNo2.class){ MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment; //then you can do whatever with the fragment theFrag.costomFunction(); }
Pero thats apenas mi acercamiento del corte y de la barra diagonal pero trabajó para mí, lo utilizo hacen relevent cambios a mi fragmento exhibido actualmente cuando el botón trasero se empuja.
Para obtener el fragmento Visible actual de ViewPager . Estoy usando esta simple declaración y está funcionando bien.
public Fragment getFragmentFromViewpager() { return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem()))); }
No es necesario llamar a getItem()
o algún otro método en una etapa posterior para obtener la referencia de un Fragment
alojado dentro de ViewPager
. Si desea actualizar algunos datos dentro de Fragment
, utilice este enfoque: ¿ Actualizar ViewPager dinámicamente?
La clave es establecer nuevos datos dentro de Adaper
y llamar a notifyDataSetChanged()
que a su vez llamará getItemPosition()
, pasándole una referencia de su Fragment
y dándole la oportunidad de actualizarlo. Todas las otras maneras requieren que usted mantenga la referencia a se oa algún otro corte que no es una buena solución.
@Override public int getItemPosition(Object object) { if (object instanceof UpdateableFragment) { ((UpdateableFragment) object).update(xyzData); } //don't return POSITION_NONE, avoid fragment recreation. return super.getItemPosition(object); }
La mejor solución es usar la extensión que creamos en CodePath llamada SmartFragmentStatePagerAdapter . Siguiendo esta guía, esto hace que la recuperación de fragmentos y el fragmento actualmente seleccionado de ViewPager sea mucho más fácil. También hace un mejor trabajo de la gestión de la memoria de los fragmentos incrustados en el adaptador.
La forma más fácil y concisa. Si todos sus fragmentos en ViewPager
son de clases diferentes, puede recuperarlos y distinguirlos de la siguiente manera:
public class MyActivity extends Activity { @Override public void onAttachFragment(Fragment fragment) { super.onAttachFragment(fragment); if (fragment.getClass() == MyFragment.class) { mMyFragment = (MyFragment) fragment; } } }
He implementado este fácil con un enfoque un poco diferente.
Mi método FragmentAdapter.getItem personalizado no devolvió MyFragment nuevo (), pero la instancia de MyFragment que se creó en el constructor FragmentAdapter.
En mi actividad, a continuación, tengo el fragmento del adaptador, comprobar si es instanceOf necesario Fragment, a continuación, moldear y utilizar los métodos necesarios.
Fragment yourFragment = yourviewpageradapter.getItem(int index);
index
es el lugar del fragmento en el adaptador como agregó fragment1
primero así que el fragment1
recuperación del fragment1
pasa como 0 y así sucesivamente para el resto
Cree un id de recurso entero en /values/integers.xml
<integer name="page1">1</integer> <integer name="page2">2</integer> <integer name="page3">3</integer>
Luego, en la función getItem de PagerAdapter:
public Fragment getItem(int position) { Fragment fragment = null; if (position == 0) { fragment = FragmentOne.newInstance(); mViewPager.setTag(R.integer.page1,fragment); } else if (position == 1) { fragment = FragmentTwo.newInstance(); mViewPager.setTag(R.integer.page2,fragment); } else if (position == 2) { fragment = FragmentThree.newInstance(); mViewPager.setTag(R.integer.page3,fragment); } return fragment; }
A continuación, en la actividad escribir esta función para obtener referencia fragmento:
private Fragment getFragmentByPosition(int position) { Fragment fragment = null; switch (position) { case 0: fragment = (Fragment) mViewPager.getTag(R.integer.page1); break; case 1: fragment = (Fragment) mViewPager.getTag(R.integer.page2); break; case 2: fragment = (Fragment) mViewPager.getTag(R.integer.page3); break; } return fragment; }
Obtenga la referencia de fragmento llamando a la función anterior y luego arrojándola a su fragmento personalizado:
Fragment fragment = getFragmentByPosition(position); if (fragment != null) { FragmentOne fragmentOne = (FragmentOne) fragment; }
Manera fácil de iterar sobre fragmentos en encargado del fragmento. Encuentra viewpager, que tiene argumento de posición de sección, colocado en public static PlaceholderFragment newInstance (int sectionNumber) .
public PlaceholderFragment getFragmentByPosition(Integer pos){ for(Fragment f:getChildFragmentManager().getFragments()){ if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) { return (PlaceholderFragment) f; } } return null; }
En Fragmento
public int getArgument(){ return mPage; { public void update(){ }
En FragmentActivity
List<Fragment> fragments = getSupportFragmentManager().getFragments(); for(Fragment f:fragments){ if((f instanceof PageFragment)&&(!f.isDetached())){ PageFragment pf = (PageFragment)f; if(pf.getArgument()==pager.getCurrentItem())pf.update(); } }
Debe extender FragmentPagerAdapter
a su clase de adaptador ViewPager.
Si utiliza FragmentStatePagerAdapter
entonces no podrá encontrar su Fragment
por su ID
public static String makeFragmentName(int viewPagerId, int index) { return "android:switcher:" + viewPagerId + ":" + index; }
Cómo utilizar este método: –
Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag( AppMethodUtils.makeFragmentName(mViewPager.getId(), i) ); InterestViewFragment newFragment = (InterestViewFragment) mFragment;
Ok para el adaptador FragmentStatePagerAdapter
Fundar una solución:
En su FragmentActivity:
ActionBar mActionBar = getSupportActionBar(); mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName()))); mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName()))); mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName()))); viewPager = (STViewPager) super.findViewById(R.id.viewpager); mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar); viewPager.setAdapter(this.mPagerAdapter);
Y crear un methode en su clase FragmentActivity – Así que ese método le da acceso a su fragmento, sólo tiene que darle la posición del fragmento que desea:
public Fragment getActiveFragment(int position) { String name = MyPagerAdapter.makeFragmentName(position); return getSupportFragmentManager().findFragmentByTag(name); }
En su adaptador:
public class MyPagerAdapter extends FragmentStatePagerAdapter { private final ActionBar actionBar; private final FragmentManager fragmentManager; public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager); this.actionBar = mActionBar; this.fragmentManager = fragmentManager; } @Override public Fragment getItem(int position) { getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit(); return (Fragment)this.actionBar.getTabAt(position); } @Override public int getCount() { return this.actionBar.getTabCount(); } @Override public CharSequence getPageTitle(int position) { return this.actionBar.getTabAt(position).getText(); } private static String makeFragmentName(int viewId, int index) { return "android:fragment:" + index; } }
Esta solución fácil funcionó bien para mí.
YourFragment fragment = (YourFragment)getSupportFragmentManager().getFragments().get(0);
(Si conoce su posición de fragmento en la lista, entonces la solución anterior funcionará)
- Diferencia entre Contexto de Actividad y Contexto de Aplicación
- Android comprobar la conexión a Internet