Cómo agregar un fragmento dentro de un ViewPager usando Nested Fragment (Android 4.2)
Tengo un ViewPager
con tres Fragments
, cada uno muestra una List
(o Grid
).
En el nuevo Android API level 17
(Jelly Bean 4.2), una de las características es Nested Fragments . La nueva descripción de la funcionalidad dice:
- Fragmento de niño que reemplaza el diseño de raíz de fragmento padre
- ¿Cómo hacer Pager Sliding Tab Strip con dos categorías igualmente encajar en la pantalla de Android?
- Múltiples páginas al mismo tiempo en un ViewPager
- NullPointerException al mostrar un ViewPager una segunda vez
- Después de la rotación, la transacción de fragmentos da IllegalStateException
Si utiliza ViewPager para crear fragmentos que deslizan hacia la izquierda y la derecha y consumen la mayoría del espacio de la pantalla, ahora puede insertar fragmentos en cada página de fragmentos.
Por lo tanto, si entiendo bien, ahora puedo crear un ViewPager
con Fragments
(con un botón dentro por ejemplo) dentro, y cuando el usuario presione el botón mostrar otro Fragment
sin perder el ViewPager
con esta nueva característica.
He gastado mi mañana tratando de implementar varias maneras diferentes, pero no puedo conseguir que funcione … ¿Puede alguien añadir un ejemplo sencillo de cómo implementar esto?
PS: Sólo estoy interesado en hacer de esta manera, con getChildFragmentManager
para aprender cómo funciona.
- Instancia de PagerAdapter en Android
- Ver Holder Pattern para ViewPager?
- Android: intenta invocar el método virtual 'void android.support.v4.app.Fragment.setMenuVisibility (boolean)' en una referencia de objeto nulo
- ViewPager + PagerAdapter muestra páginas en blanco después de los dos primeros elementos
- IllegalStateException: base de datos ya cerrada (con ViewPager)
- SetCurrentItem en ViewPager está causando excepción
- Pestañas deslizantes dentro de las pestañas de la barra de acciones
- Cómo forzar a ViewPager a volver a instanciar sus elementos
Suponiendo que ha creado los diseños xml correctos. Ahora es muy sencillo mostrar fragmentos en un ViewPager que está alojado en otro Fragmento.
El código se ve algo así en un fragmento de origen:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_parent, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewPager); mViewPager.setAdapter(new MyAdapter(getChildFragmentManager())); } public static class MyAdapter extends FragmentPagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return 4; } @Override public Fragment getItem(int position) { Bundle args = new Bundle(); args.putInt(TextViewFragment.POSITION_KEY, position); return TextViewFragment.newInstance(args); } }
Es importante utilizar Fragment.getChildFragmentManager () al instanciar el FragmentPagerAdapter. También tenga en cuenta que no puede utilizar Fragment.setRetainInstance () en los fragmentos de niños o obtendrá una excepción.
El código fuente se puede encontrar en: https://github.com/marcoRS/nested-fragments
Editar: Si desea reemplazar todo el contenido de una página en un ViewPager
, puede utilizar fragmentos anidados, pero es necesario realizar algunos cambios. Compruebe el ejemplo a continuación (la FragmentActivity
, establecer el ViewPager
y el PagerAdapter
son los mismos que el fragmento de código anterior):
// this will act as a fragment container, representing one page in the ViewPager public static class WrapperFragment extends Fragment implements ReplaceListener { public static WrapperFragment newInstance(int position) { WrapperFragment wp = new WrapperFragment(); Bundle args = new Bundle(); args.putInt("position", position); wp.setArguments(args); return wp; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { FrameLayout fl = new FrameLayout(getActivity()); fl.setId(10000); if (getChildFragmentManager().findFragmentByTag("initialTag") == null) { InitialInnerFragment iif = new InitialInnerFragment(); Bundle args = new Bundle(); args.putInt("position", getArguments().getInt("position")); iif.setArguments(args); getChildFragmentManager().beginTransaction() .add(10000, iif, "initialTag").commit(); } return fl; } // required because it seems the getChildFragmentManager only "sees" // containers in the View of the parent Fragment. @Override public void onReplace(Bundle args) { if (getChildFragmentManager().findFragmentByTag("afterTag") == null) { InnerFragment iif = new InnerFragment(); iif.setArguments(args); getChildFragmentManager().beginTransaction() .replace(10000, iif, "afterTag").addToBackStack(null) .commit(); } } } // the fragment that would initially be in the wrapper fragment public static class InitialInnerFragment extends Fragment { private ReplaceListener mListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mListener = (ReplaceListener) this.getParentFragment(); LinearLayout ll = new LinearLayout(getActivity()); Button b = new Button(getActivity()); b.setGravity(Gravity.CENTER_HORIZONTAL); b.setText("Frame " + getArguments().getInt("position")); b.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Bundle args = new Bundle(); args.putInt("positionInner", getArguments().getInt("position")); if (mListener != null) { mListener.onReplace(args); } } }); ll.setOrientation(LinearLayout.VERTICAL); ll.addView(b, new LinearLayout.LayoutParams(250, LinearLayout.LayoutParams.WRAP_CONTENT)); return ll; } } public static class InnerFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView tv = new TextView(getActivity()); tv.setText("InnerFragment in the outher Fragment with position " + getArguments().getInt("positionInner")); return tv; } } public interface ReplaceListener { void onReplace(Bundle args); }
En un vistazo rápido funciona, pero los problemas pueden aparecer como no lo he probado a mucho.
¿Puede alguien mostrar un ejemplo simple de cómo hacer esto?
El uso de fragmentos anidados parece bastante fácil, hasta que Commonsware viene con una muestra más elaborada, puedes probar el siguiente código:
public class NestedFragments extends FragmentActivity { @Override protected void onCreate(Bundle arg0) { super.onCreate(arg0); ViewPager vp = new ViewPager(this); vp.setId(5000); vp.setAdapter(new MyAdapter(getSupportFragmentManager())); setContentView(vp); } private static class MyAdapter extends FragmentPagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return WrapperFragment.newInstance(position); } @Override public int getCount() { return 8; } } public static class WrapperFragment extends Fragment { public static WrapperFragment newInstance(int position) { WrapperFragment wp = new WrapperFragment(); Bundle args = new Bundle(); args.putInt("position", position); wp.setArguments(args); return wp; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout ll = new LinearLayout(getActivity()); FrameLayout innerFragContainer = new FrameLayout(getActivity()); innerFragContainer.setId(1111); Button b = new Button(getActivity()); b.setText("Frame " + getArguments().getInt("position")); b.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { InnerFragment innerFragment = new InnerFragment(); Bundle args = new Bundle(); args.putInt("positionInner", getArguments().getInt("position")); innerFragment.setArguments(args); FragmentTransaction transaction = getChildFragmentManager() .beginTransaction(); transaction.add(1111, innerFragment).commit(); } }); ll.setOrientation(LinearLayout.VERTICAL); ll.addView(b, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); ll.addView(innerFragContainer, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); return ll; } } public static class InnerFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView tv = new TextView(getActivity()); tv.setText("InnerFragment in the outher Fragment with position " + getArguments().getInt("positionInner")); return tv; } } }
Yo era perezoso e hizo todo en código, pero estoy seguro de que puede trabajar con diseños inflados xml.
He creado un ViewPager con 3 elementos y 2 subelementos para el índice 2 y 3 y aquí lo que quería hacer ..
He implementado esto con la ayuda de preguntas y respuestas anteriores de StackOverFlow y aquí está el enlace.
ViewPagerChildFragments