Incluyendo fragments dentro de otros fragment en Android

26-12-2016 - Andrés Cruz

Incluyendo fragments dentro de otros fragment en Android
In english

Este material forma parte de mi curso y libro completo; puedes adquirirlos desde el apartado de libros y/o cursos.

Los Fragment en Android son un elemento fundamental en Android que nos permite reutilizar componentes en Android con relativa facilidad; los fragments podemos verlo como un pedazo de interfaz independiente de otros fragments y por lo tanto son muy recomendables cuando queramos desarrollar en Android; lo que puede que tal vez no sea tan claro es que dentro de los fragments podemos crear o embeber otros fragments llevando esto a un segundo nivel y aunque en primera instancia puede sonar a locura esto en realidad puede solucionar algunos problemas muy puntuales que se nos puedan plantear.

Supongamos que tenemos algún componente que está atado a nuestra actividad la cual es a primera instancia la que incrusta nuestros fragments, supongamos que dicho componente atado a nuestra actividad tiene que estar visible en toda la aplicación y que obviamente la aplicación tiene muchas pantallas como las pantallas presentadas en la siguiente imagen:

Cómo puede darse cuenta una de esas pantallas corresponde a múltiples fragments dentro de ella y según la dinámica del usuario va a ir pasando de una a otra pantalla a gusto propio.

Vamos a ponerle nombre a nuestro componente de ejemplo, supongamos que el componente es un reproductor de audio:

Reproductor android

El cual es un componente que podemos embeber dentro dentro de nuestra actividad, la cual si es destruida o recreada el reproductor se verá afectado por la misma situación cosa que no es beneficiosa, ya que la idea sería que el usuario siga escuchando la misma música sin necesidad de que esta se detenga si el mismo decide pasar de una pantalla a otra en la aplicación y aquí es una buena oportunidad para emplear los fragments que incluyen otros fragments; por ejemplo el fragment 1 que llamaremos Container1Fragment incluye otros fragments como podemos ver a continuación:

View v = inflater.inflate(R.layout.fragment_container1, container, false);

FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flGeneros, new RecyclerViewGenerosFragmentView()).commit();

Bundle bundle = new Bundle();
bundle.putInt("fragment_id", 1);
RecyclerViewArtistasFragmentView recyclerViewArtistasFragmentView = new RecyclerViewArtistasFragmentView();
recyclerViewArtistasFragmentView.setArguments(bundle);
fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flArtistas, recyclerViewArtistasFragmentView).commit();

bundle = new Bundle();
bundle.putInt("fragment_id", 2);
RecyclerViewArtistasFragmentView recyclerViewArtistasFragmentViewTop = new RecyclerViewArtistasFragmentView();
recyclerViewArtistasFragmentViewTop.setArguments(bundle);
fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flArtistasTop, recyclerViewArtistasFragmentViewTop).commit();

bundle = new Bundle();
bundle.putInt("id", 13);
bundle.putString("nombre", "");
bundle.putInt("tipo", 3);
bundle.putString("imagen", "");
RecyclerViewCancionesFragmentView recyclerViewCancionesFragmentViewLista = new RecyclerViewCancionesFragmentView();
recyclerViewCancionesFragmentViewLista.setArguments(bundle);
fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flCancionesLista, recyclerViewCancionesFragmentViewLista).commit();

No nos preocupemos mucho por los parámetros del Bundle, el objetivo es captar la idea la cual es embeber un fragment dentro de otro fragment; la vista para este fragment es la siguiente:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/llContainer1"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="#EEEEEE"
   android:orientation="vertical">

   <TextView
       style="@style/TextViewClasic"
       android:text="@string/tgeneros" />

   <FrameLayout
       android:id="@+id/flGeneros"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical"></FrameLayout>

   <TextView
       style="@style/TextViewClasic"
       android:text="@string/tartistas" />

   <FrameLayout
       android:id="@+id/flArtistas"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical"></FrameLayout>

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="1dp"
       android:background="#CCCCCC"></LinearLayout>

   <TextView
       style="@style/TextViewClasic"
       android:text="@string/ttop" />

   <FrameLayout
       android:id="@+id/flArtistasTop"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical"></FrameLayout>

   <TextView
       style="@style/TextViewClasic"
       android:text="@string/cttop" />

   <FrameLayout
       android:id="@+id/flCancionesLista"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"></FrameLayout>
</LinearLayout>

Como vemos, tenemos algunas etiquetas de guía y lo principal que son los tags FrameLayout para incluir los fragments mostrados anteriormente desde el código java.

Ahora veamos el contenido de uno de los fragments que incluiremos en Container1Fragment:

public class RecyclerViewCancionesFragmentView extends Fragment {
...
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    id = getArguments().getInt("id");
    tipo = getArguments().getInt("tipo");
    imagen = getArguments().getString("imagen");
    nombre = getArguments().getString("nombre");
    descripcion = getArguments().getString("descripcion");
    View v;

        v = inflater.inflate(R.layout.fragment_canciones, container, false);
    rvData = (RecyclerView) v.findViewById(R.id.rvData);
    tvIdentificador = (TextView) v.findViewById(R.id.tvIdentificador);
    init();

    return v;
}
...
}

Cómo podemos darnos cuenta, está últimos fragments o último nivel (segundo nivel) de fragment, es el que realmente empleamos para interactuar con el usuario, en específico (o para este ejemplo) creamos un listado a través del RecycleView pero puede hacer cualquier otra cosa como leer un código QR, un webview etc.

En nuestra actividad principal que es la que incluirá nuestro componente (por ejemplo el reproductor) entre varias cosas, hacemos lo siguiente:

...
FragmentManager fragmentManager = getSupportFragmentManager();
container1Fragment = new Container1Fragment();
fragmentManager.beginTransaction().replace(R.id.frameLayout, container1Fragment).commit();
...

Aunque aquí podemos incluir todos los fragments que queramos, en nuestro caso para no complicar mucho el experimento y la idea general de esta entrada sólo incluimos uno que es nuestro Container1Fragment.

La vista o layout de nuestra actividad es la siguiente:

<LinearLayout
   android:id="@+id/llParent"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_margin="0dp"
   android:background="#EEEEEE"
   android:orientation="vertical"
   android:padding="0dp">

   <FrameLayout
       android:id="@+id/frameLayout"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginBottom="200px"
       android:layout_marginLeft="10dp"
       android:layout_marginRight="10dp"
       android:orientation="vertical"></FrameLayout>

   <LinearLayout
       android:id="@+id/llContainerR"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="bottom"
       android:orientation="vertical"
       android:textAppearance="@style/TextAppearance.AppCompat.Body1" />

</LinearLayout>

Ahora, para variar el contenido de cada fragment (primer nivel) o sustituir algunos según la acción ejercida por el usuario para este experimento para nuestro caso empleamos los Adapters, es decir, nuestro experimento está compuesto de puros listados y cuando el usuario realiza un clic (toca uno de los elementos del listado) se ejecuta un evento el cual actualiza toda la pantalla (reemplaza el contenido de Container1Fragment por ejemplo) muestra otro fragment o conjunto de fragments embebidos o cualquier otra cosa que queramos dependiendo de nuestras necesidades; en este ejemplo, el evento clic reemplaza el contenido del fragment principal es decir Container1Fragment:

...
artistaViewHolder.llContainer.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        Bundle bundle = new Bundle();
        bundle.putInt("id", artista.getArtista_id());
        bundle.putInt("album_id", 0);
        bundle.putInt("tipo", 1);
        bundle.putString("imagen", artista.getImagen_url());
        bundle.putString("nombre", artista.getNombre());

        Container2Fragment container2Fragment = new Container2Fragment();
        container2Fragment.setArguments(bundle);

        FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.frameLayout, container2Fragment).addToBackStack(NULL).commit();
    }
});
...

El resto del código del adaptador es el tradicional (inicialización de las variables y layouts y poco más); como podemos darnos cuenta, a través del método clic del adaptador reemplazamos el Container1Fragment con Container2Fragment, lo que a efectos es reemplazar todo el contenido de una ventana con otro contenido.

Por lo tanto solo mantenemos una sola actividad pero podemos variar las pantallas de las mismas fácilmente con los fragments que embebe la actividad y con los fragments embebidos por otros fragments y de esta forma garantizamos que nuestra actividad no será destruida mientras el usuario navega por la aplicación y tampoco nuestro componente o reproductor de música según sea el caso.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.

!Cursos a!

10$

En Udemy

Quedan días!

Ver los cursos
¡Hazte afiliado en Gumroad!

!Cursos desde!

4$

En Academia

Ver los cursos

!Libros desde!

1$

Ver los libros
!Web Alojada en Hostinger!