Insertar y quitar fragmentos en viewpager correctamente
Estoy haciendo una aplicación de adroid con viewpager y fragmentos. Quiero hacer una opción para agregar o quitar páginas de fragmentos al buscapersonas dinámicamente. Tengo un FragmentPagerAdapter personalizado:
public class MyAdapter extends FragmentPagerAdapter implements TitleProvider{ protected final List<PageFragment> fragments; /** * @param fm * @param fragments */ public MyAdapter(FragmentManager fm, List<PageFragment> fragments) { super(fm); this.fragments = fragments; } public void addItem(PageFragment f){ fragments.add(f); notifyDataSetChanged(); } public void addItem(int pos, PageFragment f){ for(int i=0;i<fragments.size();i++){ if(i>=pos){ getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(i))).commit(); } } fragments.add(pos,f); notifyDataSetChanged(); pager.setAdapter(this); pager.setCurrentItem(pos); } public void removeItem(int pos){ getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(pos))).commit(); for(int i=0;i<fragments.size();i++){ if(i>pos){ getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(i))).commit(); } } fragments.remove(pos); notifyDataSetChanged(); pager.setAdapter(this); if(pos<fragments.size()){ pager.setCurrentItem(pos); }else{ pager.setCurrentItem(pos-1); } } @Override public Fragment getItem(int position) { return fragments.get(position).toFragment(); } @Override public int getCount() { return fragments.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } private String getFragmentTag(int pos){ return "android:switcher:"+R.id.pager+":"+pos; } public String getTitle(int position) { String name = fragments.get(position).getName(); if(name.equals("")) return "- "+position+" -"; return name; } }
Puedo quitar cualquier fragmento excepto el 0. cuando intento quitarlo Conseguí un NullPointerException en el notifyDataSetChanged (); O en el pager.setAdapter (este); Si comento la notificación.
- El cajón de navegación se cierra al hacer clic
- Android - guardar / restaurar estado de fragmento
- Fragmento crear / restaurar una vista duplicada cuando vuelva a conectar
- La barra de acción se mueve hacia abajo mientras se reemplaza con fragmento
- Fragment onResume () no se llama cuando se utiliza FragmentPagerAdapter
También obtuve una NullPointerException cuando intento insertar una nueva página. Cuando agrego la nueva página al final de la lista está trabajando muy bien. Incluso traté de readd los fragmentos en el inserto con esto después de los fragmentos.add (pos, f)
for(int i=0;i<fragments.size();i++){ if(i>=pos){ getSupportFragmentManager().beginTransaction().add(fragments.get(i).toFragment(),getFragmentTag(i-1)).commit(); } }
Si utilizo getFragmentTag(i-1)
tengo nullpointer de nuevo. Con el uso de i
sólo obtuve illegalstateexception porque no se puede modificar la etiqueta del fragmento. Con beginTransaction().add(pager.getId,fragments.get(i).toFragment())
sigue siendo nullpointer …
Mi pregunta es: ¿qué estoy haciendo mal, y cómo se puede hacer correctamente? (Y tal vez: de donde notyfyDataSetChanged()
obtener los datos cuando las causas nullpointerexception?)
- Cambio de orientación con viewPager dentro de FragmentActivity
- Abre la actividad A y carga un fragmento específico de la actividad A de la actividad B
- Mapfragment findFragmentById siempre null
- Error de Android - getListView () en ListFragment
- ViewPager FragmentPagerAdapter Nullpointer
- Cómo descartar un DialogFragment al presionar fuera del cuadro de diálogo?
- Ocultar el teclado en fragmento en el exterior haga clic
- ViewPager onClickListener hace referencia a la vista errónea en android
Esto es lo que he utilizado para resolver el problema con fragmentos que se etiquetan cuando instanciado y el hecho de que los fragmentos marcados anteriormente no pueden cambiar de posición dentro de ViewPager al intentar agregar o quitar páginas, es decir, obtener la excepción:
Java.lang.IllegalStateException: No se puede cambiar la etiqueta del fragmento MyFragment {4055f558 id = 0x7f050034 android: switcher: 2131034164: 3}: android: switcher: 2131034164: 3 ahora android: switcher: 2131034164: 4
Este adaptador se crea con una lista de todas las páginas por adelantado y puede utilizar setEnabled (int position, boolean enabled) para deshabilitar o activar ciertas páginas que ocultan o muestran estas páginas en ViewPager.
Funciona manteniendo una lista interna de todos los fragmentos pero exponiéndose al ViewPager y asignando las posiciones de los fragmentos habilitados solamente.
public class DynamicFragmentPagerAdapter extends FragmentPagerAdapter { public final ArrayList<Fragment> screens = new ArrayList<Fragment>(); private Context context; private List<AtomicBoolean> flags = new ArrayList<AtomicBoolean>(); public DynamicFragmentPagerAdapter(FragmentManager fm, Context context, List<Class<?>> screens) { super(fm); this.context = context; for(Class<?> screen : screens) addScreen(screen, null); notifyDataSetChanged(); } public DynamicFragmentPagerAdapter(FragmentManager fm, Context context, Map<Class<?>, Bundle> screens) { super(fm); this.context = context; for(Class<?> screen : screens.keySet()) addScreen(screen, screens.get(screen)); notifyDataSetChanged(); } private void addScreen(Class<?> clazz, Bundle args) { screens.add(Fragment.instantiate(context, clazz.getName(), args)); flags.add(new AtomicBoolean(true)); } public boolean isEnabled(int position) { return flags.get(position).get(); } public void setEnabled(int position, boolean enabled) { AtomicBoolean flag = flags.get(position); if(flag.get() != enabled) { flag.set(enabled); notifyDataSetChanged(); } } @Override public int getCount() { int n = 0; for(AtomicBoolean flag : flags) { if(flag.get()) n++; } return n; } @Override public Fragment getItem(int position) { return screens.get(position); } @Override public int getItemPosition(Object object) { return POSITION_NONE; // To make notifyDataSetChanged() do something } @Override public void notifyDataSetChanged() { try { super.notifyDataSetChanged(); } catch (Exception e) { Log.w("", e); } } private List<Fragment> getEnabledScreens() { List<Fragment> res = new ArrayList<Fragment>(); for(int n = 0; n < screens.size(); n++) { if(flags.get(n).get()) res.add(screens.get(n)); } return res; } @Override public Object instantiateItem(ViewGroup container, int position) { // We map the requested position to the position as per our screens array list Fragment fragment = getEnabledScreens().get(position); int internalPosition = screens.indexOf(fragment); return super.instantiateItem(container, internalPosition); } @Override public CharSequence getPageTitle(int position) { Fragment fragment = getEnabledScreens().get(position); if(fragment instanceof TitledFragment) return ((TitledFragment)fragment).getTitle(context); return super.getPageTitle(position); } public static interface TitledFragment { public String getTitle(Context context); } }
Tengo una solución que funciona con un adaptador no basado en fragmentos. Echa un vistazo a mi mensaje y ver si ayuda.
Puedo quitar cualquier fragmento excepto el 0.
Para mi funciona si solo usas una condición> = whitin en el loop forIl de removeItem:
if (i >= pos){ fm.beginTransaction().remove(fragments.get(i).getFragment()).commit(); }
- Publicar texto diferente en facebook y twitter utilizando las intenciones de Android
- ¿Responde automáticamente la llamada entrante mediante programación?