Skip to content

Most visited

Recently visited

navigation

Fragmentos

Un Fragment representa un comportamiento o una parte de la interfaz de usuario en una Activity. Puedes combinar múltiples fragmentos en una sola actividad para crear una IU multipanel y volver a usar un fragmento en múltiples actividades. Puedes pensar en un fragmento como una sección modular de una actividad que tiene su ciclo de vida propio, recibe sus propios eventos de entrada y que puedes agregar o quitar mientras la actividad se esté ejecutando (algo así como una "subactividad" que puedes volver a usar en diferentes actividades).

Un fragmento siempre debe estar integrado a una actividad y el ciclo de vida del fragmento se ve directamente afectado por el ciclo de vida de la actividad anfitriona. Por ejemplo, cuando la actividad está pausada, también lo están todos sus fragmentos, y cuando la actividad se destruye, lo mismo ocurre con todos los fragmentos. Sin embargo, mientras una actividad se está ejecutando (está en el estado del ciclo de vida reanudada ), puedes manipular cada fragmento de forma independiente; por ejemplo, para agregarlos o quitarlos. Cuando realizas una transacción de fragmentos como esta, también puedes agregarlos a una pila de actividades administrada por la actividad; cada entrada de la pila de actividades en la actividad es un registro de la transacción de fragmentos realizada. La pila de actividades le permite al usuario invertir una transacción de fragmentos (navegar hacia atrás) al presionar el botón Atrás.

Cuando agregas un fragmento como parte del diseño de tu actividad, este se ubica en ViewGroup, dentro de la jerarquía de vistas de la actividad y el fragmento define su propio diseño de vista. Puedes insertar un fragmento en el diseño de tu actividad declarando el fragmento en el archivo de diseño de la actividad como elemento <fragment> o agregándolo a un ViewGroup existente desde el código de tu aplicación. Sin embargo, no es necesario que un fragmento forme parte del diseño de la actividad; también puedes usar un fragmento con su IU propia, como un trabajador invisible para la actividad.

Este documento describe cómo crear tu aplicación para usar fragmentos, incluido cómo los fragmentos pueden mantener su estado cuando se los agrega a la pila de actividades de la actividad, cómo pueden compartir eventos con la actividad y con otros fragmentos en la actividad, cómo pueden contribuir con la barra de acciones de la actividad, etc.

Filosofía de diseño

Android introduce los fragmentos en Android 3.0 (nivel de API 11), principalmente para admitir diseños de IU más dinámicos y flexibles en pantallas grandes, como las de las tablets. Como la pantalla de una tablet es mucho más grande que la de un teléfono, hay más espacio para combinar e intercambiar componentes de la IU. Los fragmentos admiten esos diseños sin la necesidad de que administres cambios complejos en la jerarquía de vistas. Al dividir el diseño de una actividad en fragmentos, puedes modificar el aspecto de la actividad durante el tiempo de ejecución y conservar esos cambios en una pila de actividades administrada por la actividad.

Por ejemplo, una aplicación de noticias puede usar un fragmento para mostrar una lista de artículos a la izquierda y otro fragmento para mostrar un artículo a la derecha; ambos fragmentos aparecen en una actividad, uno al lado del otro, y cada fragmento tiene su propio conjunto de métodos callback del ciclo de vida y administran sus propios eventos de entrada del usuario. Entonces, en lugar de usar una actividad para seleccionar un artículo y otra actividad para leer el artículo, el usuario puede seleccionar un artículo y leerlo dentro de la misma actividad, tal como se ilustra en el diseño de tablet en la figura 1.

Debes diseñar cada fragmento como un componente modular y reutilizable de la actividad. Como cada fragmento define su propio diseño y su propio comportamiento con sus propios callbacks del ciclo de vida, puedes incluir un fragmento en múltiples actividades; por lo tanto, debes diseñarlo para volver a utilizarlo y evitar la manipulación directa de un fragmento desde otro fragmento. Esto es muy importante porque un fragmento modular te permite cambiar tus combinaciones de fragmentos para diferentes tamaños de pantalla. Cuando diseñas tu aplicación para que admita tablets y teléfonos, puedes reutilizar tus fragmentos en diferentes configuraciones de diseño para optimizar la experiencia del usuario en función del espacio de pantalla disponible. Por ejemplo, en un teléfono, podría ser necesario separar los fragmentos para proporcionar una IU de panel único cuando no quepa más de uno en la misma actividad.

Figura 1: Ejemplo de la manera en que dos módulos de la IU definidos por fragmentos se pueden combinar en una actividad para un diseño de tablet y se presentan por separado para un diseño de teléfono.

Por ejemplo, para continuar con el ejemplo de la aplicación de noticias, la aplicación puede integrar dos fragmentos en la Actividad A cuando se ejecuta en un dispositivo del tamaño de una tablet. Sin embargo, en una pantalla de teléfono, no hay suficiente espacio para ambos fragmentos, por lo que la Actividad A incluye solo el fragmento para la lista de artículos, y cuando el usuario selecciona un artículo, se inicia la Actividad B, que incluye el segundo fragmento para poder leer el artículo. Por lo tanto, la aplicación admite tablets y teléfonos al reutilizar fragmentos en diferentes combinaciones, como se ilustra en la figura 1.

Para obtener más información acerca de cómo diseñar tu aplicación con diferentes combinaciones de fragmentos para diferentes configuraciones de pantalla, lee la guía Tablets y teléfonos compatibles.

Crear un fragmento

Figura 2: Ciclo de vida de un fragmento (mientras su actividad está ejecución).

Para crear un fragmento, debes crear una subclase Fragment (o una subclase existente de ella). La clase Fragment tiene un código que se asemeja bastante a una Activity. Contiene métodos callback similares a los de una actividad, como onCreate(), onStart(), onPause() y onStop(). De hecho, si estás convirtiendo una aplicación de Android existente para utilizar fragmentos, deberías simplemente trasladar código de los métodos callback de tu actividad a los métodos callback respectivos de tu fragmento.

Generalmente, debes implementar al menos los siguientes métodos del ciclo de vida:

onCreate()
El sistema lo llama cuando crea el fragmento. En tu implementación, debes inicializar componentes esenciales del fragmento que quieres conservar cuando el fragmento se pause o se detenga y luego se reanude.
onCreateView()
El sistema lo llama cuando el fragmento debe diseñar su interfaz de usuario por primera vez. Para diseñar una IU para tu fragmento, debes devolver una View desde este método que será la raíz del diseño de tu fragmento. Puedes devolver nulo su el fragmento no proporciona una IU.
onPause()
El sistema llama a este método como el primer indicador de que el usuario está abandonando el fragmento (aunque no siempre significa que el fragmento se esté destruyendo). Generalmente este es el momento en el que debes confirmar los cambios que deban conservarse más allá de la sesión de usuario actual (porque es posible que el usuario no vuelva).

La mayoría de las aplicaciones deben implementar al menos estos tres métodos para cada fragmento, pero hay muchos otros métodos callback que también debes usar para manipular varias fases del ciclo de vida del fragmento. Todos los métodos callback del ciclo de vida se discuten en más detalle más adelante en la sección Manipulación del ciclo de vida del fragmento.

Existen también algunas subclases que quizá desees extender, en lugar de la clase de base Fragment:

DialogFragment
Muestra un diálogo flotante. Usar esta clase para crear un diálogo es una buena alternativa al uso de métodos del asistente de diálogos en la clase Activity, ya que puedes incorporar un diálogo del fragmento en la pila de actividades de fragmentos administrados por la actividad, lo que le permite al usuario volver a un fragmento descartado.
ListFragment
Muestra una lista de elementos administrados por un adaptador (como un SimpleCursorAdapter, al igual que ListActivity. Proporciona varios métodos para administrar una vista de lista, como el callback onListItemClick() para manipular eventos de clic.
PreferenceFragment
Muestra una jerarquía de objetos Preference en forma de lista, al igual que PreferenceActivity. Esto resulta útil para crear una actividad "configuración" para tu aplicación.

Agregar una interfaz de usuario

Un fragmento generalmente se usa como parte de la interfaz de usuario de una actividad y aporta su propio diseño a la actividad.

Para proporcionar un diseño para un fragmento, debes implementar el método de callback onCreateView(), al cual el sistema Android llama cuando llega el momento de que el fragmento defina su diseño. Tu implementación de este método debe devolver una View que es la raíz del diseño de tu fragmento.

Nota: Si tu fragmento es una subclase de ListFragment, la implementación predeterminada muestra una ListView desde onCreateView(), de modo que no necesitas implementarla.

Para mostrar un diseño desde onCreateView(), puedes agrandarlo desde un recurso de diseño definido en XML. Para ayudarte a hacerlo, onCreateView() proporciona un objeto LayoutInflater.

Por ejemplo, a continuación se muestra una subclase de Fragment que carga un diseño desde el archivo example_fragment.xml:

public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

El parámetro container que se pasa a onCreateView() es el ViewGroup principal (del diseño de la actividad) en el cual se insertará el diseño de tu fragmento. El parámetro savedInstanceState es un Bundle que proporciona datos acerca de la instancia previa del fragmento, si el fragmento se está reanudando (la restauración del estado se discute en más detalle en la sección Manipulación del ciclo de vida del fragmento).

El método inflate() adopta tres argumentos:

Ya viste cómo crear un fragmento que proporcione un diseño. Ahora deberás agregar el fragmento a tu actividad.

Agregar un fragmento a una actividad

Generalmente, un fragmento aporta una parte de la IU a la actividad anfitriona, que se integra como parte de la jerarquía de vistas general de la actividad. Existen dos maneras de agregar un fragmento al diseño de la actividad:

Agregar un fragmento sin una IU

Los ejemplos anteriores muestran cómo agregar un fragmento a tu actividad para poder proporcionar una IU. Sin embargo, también puedes usar un fragmento para proporcionar un comportamiento en segundo plano para la actividad sin presentar una IU adicional.

Para agregar un fragmento sin IU, agrega el fragmento desde la actividad con add(Fragment, String) (debes proporcionar una “etiqueta” de string única para el fragmento, en lugar de un ID de vista). Esto agrega el fragmento; sin embargo, debido a que no está asociado a una vista en el diseño de la actividad, no recibe una llamada para onCreateView(). Por lo tanto, no necesitas implementar ese método.

No solo puedes proporcionar una etiqueta de string para fragmentos sin IU (también puedes hacerlo para fragmentos que tienen una IU), pero si el fragmento no tiene una IU la etiqueta de string es la única manera de identificarlo. Si más adelante quieres obtener el fragmento de la actividad, debes usar findFragmentByTag().

Para acceder a una actividad de ejemplo que usa un fragmento como trabajador en segundo plano sin IU, lee el ejemplo FragmentRetainInstance.java incluido en los ejemplos de SDK (disponible a través de Android SDK Manager) que se encuentra en tu sistema como <sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java.

Administración de fragmentos

Para administrar los fragmentos de tu actividad, debes usar FragmentManager. Para obtenerlo, llama a getFragmentManager() desde tu actividad.

Algunas de las cosas que puedes hacer con FragmentManager incluyen:

Para obtener más información acerca de estos y otros métodos, consulta los documentos sobre la clase FragmentManager.

Como se mostró en la sección anterior, también puedes usar FragmentManager para abrir una FragmentTransaction, que te permite realizar transacciones como agregar y quitar fragmentos.

Realización de transacciones de fragmentos

Una excelente característica acerca del uso de fragmentos en tu actividad es la capacidad de agregar, quitar, reemplazar y realizar otras acciones con ellos en respuesta a la interacción del usuario. Cada conjunto de cambios que confirmas en la actividad recibe la denominación de transacción y puedes realizar una usando las API de FragmentTransaction. También puedes guardar cada transacción en una pila de actividades administrada por la actividad, lo que le permitirá al usuario navegar hacia atrás por los cambios realizados en el fragmento (como navegar hacia atrás en las actividades).

Puedes adquirir una instancia de FragmentTransaction de FragmentManager como esta:

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Cada transacción es un conjunto de cambios que quieres realizar al mismo tiempo. Puedes configurar todos los cambios que desees realizar en una transacción determinada con métodos como add(), remove() y replace(). Luego, para aplicar la transacción a la actividad, debes llamar a commit().

Sin embargo, antes de llamar a commit() probablemente te convenga llamar a addToBackStack() para agregar la transacción a una pila de retroceso de transacciones de fragmentos. Esta pila de actividades está administrada por la actividad y le permite al usuario volver a un estado anterior del fragmento presionando el botón Atrás.

Por ejemplo, aquí te mostramos cómo puedes reemplazar un fragmento por otro y conservar el estado anterior en la pila de actividades:

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

En este ejemplo, newFragment reemplaza al fragmento (si lo hubiera) que se encuentra actualmente en el contenedor de diseño identificado con el ID R.id.fragment_container. Al llamar a addToBackStack(), la transacción de reemplazo se guarda en la pila de retroceso para que el usuario pueda revertir la transacción y recuperar el fragmento previo presionando el botón Atrás.

Si agregas varios cambios a la transacción (como otro add() o remove()) y llamas a addToBackStack(), todos los cambios aplicados antes de llamar a commit() se agregarán a la pila de retroceso como una transacción única, y el botón Atrás los revertirá juntos.

No importa el orden en que agregues cambios a una FragmentTransaction, excepto por lo siguiente:

Si no llamas a addToBackStack(), cuando realices una transacción que quite un fragmento, ese fragmento se destruirá cuando se confirme la transacción y el usuario no podrá regresar a él. Pero si llamas a addToBackStack(), cuando se elimine un fragmento, el fragmento se detendrá y se reanudará si el usuario retrocede en la navegación.

Sugerencia: Para cada transacción de fragmentos, puedes aplicar una animación de transición llamando a setTransition() antes de confirmar.

Si llamas a commit(), la transacción no se realizará de inmediato sino que se programa para ejecutarse en el subproceso de la IU de la actividad (el subproceso "principal") tan pronto el subproceso pueda hacerlo. Sin embargo, si es necesario, puedes llamar a executePendingTransactions() desde el subproceso de tu IU para ejecutar de inmediato transacciones enviadas por commit(). Generalmente no es necesario hacer esto a menos que la transacción sea una dependencia para tareas de otros subprocesos.

Advertencia: Puedes confirmar una transacción con commit() solo antes de que la actividad guarde su estado (cuando el usuario la abandone). Si intentas confirmar después de ese momento, se producirá una excepción. Esto ocurre porque se podría perder el estado después de la confirmación si fuera necesario restaurar la actividad. En situaciones en las cuales no importe perder la confirmación, usa commitAllowingStateLoss().

Comunicación con la actividad

Si bien un Fragment se implementa como un objeto dependiente de una Activity y puede usarse dentro de múltiples actividades, una instancia determinada de un fragmento está directamente vinculada a la actividad que la contiene.

Específicamente, el fragmento puede acceder a la instancia Activity con getActivity() y realizar tareas de manera sencilla, como buscar una vista en el diseño de la actividad:

View listView = getActivity().findViewById(R.id.list);

De la misma manera, tu actividad puede llamar a métodos del fragmento mediante la adquisición de una referencia al Fragment desde FragmentManager usando findFragmentById() o findFragmentByTag(). Por ejemplo:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

Crear callbacks de eventos a la actividad

En algunos casos, podrías necesitar que un fragmento comparta eventos con la actividad. Una buena manera de hacerlo es definir una interfaz callback dentro del fragmento y exigirle a la actividad anfitriona que la implemente. Cuando la actividad reciba un callback a través de la interfaz, podrá compartir la información con otros fragmentos del diseño, según sea necesario.

Por ejemplo, si una aplicación de noticias tiene dos fragmentos en una actividad, uno para mostrar una lista de artículos (fragmento A) y otro para exhibir un artículo (fragmento B), el fragmento A debe indicarle a la actividad cuando se seleccione un elemento de la lista para que pueda informarle al fragmento B que debe exhibir el artículo. En este caso, la interfaz OnArticleSelectedListener se declara dentro del fragmento A:

public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

Luego, la actividad que aloja al fragmento implementa la interfaz OnArticleSelectedListener y anula onArticleSelected() para notificar al fragmento B sobre el evento del fragmento A. Para garantizar que la actividad host implemente esta interfaz, el método de callback onAttach() del fragmento A (al cual el sistema llama cuando agrega el fragmento a la actividad) crea una instancia de OnArticleSelectedListener ordenando la Activity que se pasa a onAttach():

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

Si la actividad no implementó la interfaz, el fragmento produce una ClassCastException. Si se realiza con éxito, el miembro mListener conserva una referencia a la implementación de OnArticleSelectedListener por parte de la actividad para que el fragmento A pueda compartir eventos con esta llamando a los métodos definidos por la interfaz OnArticleSelectedListener. Por ejemplo, si el fragmento A es una extensión de ListFragment, cada vez que el usuario haga clic en un elemento de la lista, el sistema llamará a onListItemClick() en el fragmento, que luego llama a onArticleSelected() para compartir el evento con la actividad.

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

El parámetro id que se pasa a onListItemClick() es el ID de la fila del elemento en el cual se hizo clic, que la actividad (u otro fragmento) usa para capturar el artículo del ContentProvider de la aplicación.

Puedes encontrar más información acerca de cómo usar un proveedor de contenido en el documento Proveedores de contenido.

Agregar artículos a la barra de app

Tus fragmentos pueden aportar elementos de menú al menú de opciones de la actividad (y, en consecuencia, a la barra de app) implementando onCreateOptionsMenu(). Sin embargo, para que este método pueda recibir llamadas, debes llamar a setHasOptionsMenu() durante onCreate() para indicar que el fragmento intenta agregar elementos al menú de opciones (de lo contrario, el fragmento no recibirá una llamada a onCreateOptionsMenu()).

Los elementos que agregues al Menú de opciones desde el fragmento se anexan a los elementos del menú existentes. El fragmento también recibe callbacks a onOptionsItemSelected() cuando se selecciona un elemento del menú.

También puedes registrar una vista en el diseño de tu fragmento para proporcionar un menú contextual llamando a registerForContextMenu(). Cuando el usuario abre el menú contextual, el fragmento recibe una llamada a onCreateContextMenu(). Cuando el usuario selecciona un elemento, el fragmento recibe una llamada a onContextItemSelected().

Nota: Si bien tu fragmento recibe un callback en relación con el elemento seleccionado para cada elemento de menú que agrega, la actividad será la que primero reciba el callback correspondiente cuando el usuario seleccione un elemento del menú. Si la implementación que realiza la actividad del callback en relación con el elemento seleccionado no aborda el elemento seleccionado, el evento se pasa al callback del fragmento. Esto ocurre con el Menú de opciones y los menús contextuales.

Para obtener más información acerca de los menús, consulta la guía para desarrolladores Menús y la clase de capacitación Barra de app.

Manipulación del ciclo de vida del fragmento

Figura 3: Efecto del ciclo de vida de la actividad en el ciclo de vida del fragmento.

La administración del ciclo de vida de un fragmento se parece mucho a la administración del ciclo de vida de una actividad. Al igual que una actividad, un fragmento puede tener tres estados:

Reanudada
El fragmento está visible en la actividad que se está ejecutando.
Pausada
Otra actividad se encuentra en primer plano y tiene el foco, pero la actividad en la que reside este fragmento aún está visible (la actividad en segundo plano es parcialmente transparente o no cubre toda la pantalla).
Detenida
El fragmento no está visible. O bien se detuvo la actividad anfitriona o se quitó el fragmento de la actividad, pero se agregó a la pila de actividades. Un fragmento detenido aún está activo (el sistema conserva el estado y la información de miembro). No obstante, ya no está visible para el usuario y se cerrará si se cierra la actividad.

Como también ocurre con una actividad, puedes conservar el estado de un fragmento usando un Bundle, en caso de que se cierre el proceso de la actividad y debas restaurar el estado del fragmento cuando se vuelva a crear la actividad. Puedes guardar el estado durante el callback de onSaveInstanceState() del fragmento y restaurarlo durante onCreate(), onCreateView() o onActivityCreated(). Para obtener más información acerca de cómo guardar el estado, lee el documento Actividades .

La diferencia más importante en el ciclo de vida entre una actividad y un fragmento es cómo cada uno se almacena en su pila de actividades respectiva. Cuando se detiene una actividad, de forma predeterminada, se dispone en una pila de actividades administrada por el sistema (de modo que el usuario pueda navegar hasta ella con el botón Atrás, como se observa en Tareas y pila de retroceso). Sin embargo, un fragmento se dispone en una pila de retroceso administrada por la actividad anfitriona solo cuando solicitas explícitamente que se guarde la instancia mediante la llamada a addToBackStack() durante una transacción que elimina el fragmento.

De lo contrario, la administración del ciclo de vida del fragmento es muy similar a la administración del ciclo de vida de la actividad. Por lo tanto, las mismas prácticas que se aplican para la administración del ciclo de vida de la actividad también se aplican a los fragmentos. También debes comprender cómo la vida de la actividad afecta la vida del fragmento.

Advertencia: Si necesitas un objeto Context en tu Fragment, puedes llamar a getActivity(). Pero asegúrate de llamar a getActivity() solo cuando el fragmento esté anexado a una actividad. Cuando el fragmento aún no se haya anexado, o se haya separado durante el final de su ciclo de vida, getActivity() devolverá nulo.

Coordinación con el ciclo de vida de la actividad

El ciclo de vida de la actividad en la que reside el fragmento afecta directamente al ciclo de vida del fragmento, de modo que cada callback del ciclo de vida para la actividad genera un callback similar para cada fragmento. Por ejemplo, cuando la actividad recibe onPause(), cada fragmento en la actividad recibe onPause().

No obstante, los fragmentos tienen algunos callbacks del ciclo de vida adicionales que abordan la interacción única con la actividad para poder realizar acciones como crear y destruir la IU del fragmento. Estos métodos de callback adicionales son los siguientes:

onAttach()
Reciba una llamada cuando se asocia el fragmento con la actividad (aquí se pasa Activity).
onCreateView()
Se lo llama para crear la jerarquía de vistas asociada con el fragmento.
onActivityCreated()
Se lo llama cuando el método onCreate() de la actividad realiza un callback.
onDestroyView()
Se lo llama cuando se quita la jerarquía de vistas asociada con el fragmento.
onDetach()
Se lo llama cuando se desasocia el fragmento de la actividad.

En la figura 3 se ilustra el flujo del ciclo de vida de un fragmento, afectado por la actividad que lo aloja. En esta figura, puedes ver la manera en que cada estado sucesivo de la actividad determina los métodos de callback que un fragmento puede recibir. Por ejemplo, cuando la actividad recibe su callback de onCreate(), un fragmento en la actividad recibe el callback de onActivityCreated().

Una vez que la actividad alcanza el estado de "reanudada", puedes agregar y quitar libremente fragmentos en esa actividad. De este modo, solo cuando la actividad se encuentra en estado de "reanudada" el ciclo de vida de un fragmento puede cambiar de forma independiente.

No obstante, cuando la actividad sale del estado de "reanudada" hace que el fragmento vuelva a atravesar su ciclo de vida.

Ejemplo

Para agrupar todo lo que se discutió en este documento, aquí te mostramos un ejemplo de una actividad que usa dos fragmentos para crear un diseño con dos paneles. La actividad a continuación incluye un fragmento para mostrar una lista de título de obras de Shakespeare y otro para mostrar un resumen de la obra cuando se la seleccione de la lista. También demuestra cómo proporcionar diferentes configuraciones de fragmentos en función de la configuración de pantalla.

Nota: El código fuente completo para esta actividad está disponible en FragmentLayout.java.

La actividad principal aplica un diseño de la forma habitual, durante onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.fragment_layout);
}

El diseño aplicado es fragment_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
            android:id="@+id/titles" android:layout_weight="1"
            android:layout_width="0px" android:layout_height="match_parent" />

    <FrameLayout android:id="@+id/details" android:layout_weight="1"
            android:layout_width="0px" android:layout_height="match_parent"
            android:background="?android:attr/detailsElementBackground" />

</LinearLayout>

Con este diseño, el sistema crea una instancia de TitlesFragment (que incluye los títulos de las obras) no bien la actividad carga el diseño, mientras FrameLayout (donde irá el fragmento para mostrar el resumen de la obra) ocupa espacio en el lado derecho de la pantalla, pero primero permanece vacío. Como verás a continuación, el fragmento se coloca en el FrameLayout solo cuando el usuario selecciona un elemento de la lista.

Sin embargo, no todas las configuraciones de pantalla son lo suficientemente anchas para mostrar la lista de obras y el resumen, una al lado de la otra. Por lo tanto, el diseño anterior se usa únicamente para la configuración de pantalla horizontal al guardarse en res/layout-land/fragment_layout.xml.

De este modo, cuando la pantalla se encuentre en posición vertical, el sistema aplica el siguiente diseño, que se guarda en res/layout/fragment_layout.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
            android:id="@+id/titles"
            android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>

Este diseño incluye únicamente TitlesFragment. Esto significa que, cuando el dispositivo esté en orientación vertical, solo estará visible la lista de títulos de obras. Y cuando el usuario haga clic en un elemento de la lista en esta configuración, la aplicación iniciará una nueva actividad para mostrar el resumen, en lugar de cargar un segundo fragmento.

A continuación puedes ver cómo se logra esto en las clases de fragmentos. El primer fragmento es TitlesFragment, que muestra la lista de títulos de obras de Shakespeare. Este fragmento extiende ListFragment y depende de él para administrar gran parte del trabajo de la vista de lista.

Mientras analizas este código, ten en cuenta que cuando el usuario hace clic en un elemento de la lista se pueden tener lugar dos comportamientos: según cuál de los dos diseños esté activo, se puede crear y exhibir un nuevo fragmento para mostrar los detalles en la misma actividad (agregar el fragmento a FrameLayout, o iniciar una nueva actividad (en la que se puede mostrar el fragmento).

public static class TitlesFragment extends ListFragment {
    boolean mDualPane;
    int mCurCheckPosition = 0;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Populate list with our static array of titles.
        setListAdapter(new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));

        // Check to see if we have a frame in which to embed the details
        // fragment directly in the containing UI.
        View detailsFrame = getActivity().findViewById(R.id.details);
        mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;

        if (savedInstanceState != null) {
            // Restore last state for checked position.
            mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
        }

        if (mDualPane) {
            // In dual-pane mode, the list view highlights the selected item.
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            // Make sure our UI is in the correct state.
            showDetails(mCurCheckPosition);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("curChoice", mCurCheckPosition);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        showDetails(position);
    }

    /**
     * Helper function to show the details of a selected item, either by
     * displaying a fragment in-place in the current UI, or starting a
     * whole new activity in which it is displayed.
     */
    void showDetails(int index) {
        mCurCheckPosition = index;

        if (mDualPane) {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is currently shown, replace if needed.
            DetailsFragment details = (DetailsFragment)
                    getFragmentManager().findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index) {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                if (index == 0) {
                    ft.replace(R.id.details, details);
                } else {
                    ft.replace(R.id.a_item, details);
                }
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        } else {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }
}

El segundo fragmento, DetailsFragment, muestra el resumen de la obra para el elemento seleccionado de la lista de TitlesFragment:

public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist.  The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // won't be displayed.  Note this is not needed -- we could
            // just run the code below, where we would create and return
            // the view hierarchy; it would just never be used.
            return null;
        }

        ScrollView scroller = new ScrollView(getActivity());
        TextView text = new TextView(getActivity());
        int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                4, getActivity().getResources().getDisplayMetrics());
        text.setPadding(padding, padding, padding, padding);
        scroller.addView(text);
        text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
        return scroller;
    }
}

Recuerda, de la clase TitlesFragment, que si el usuario hace clic en un elemento de la lista y el diseño actual no incluye la vista R.id.details (donde DetailsFragment pertenece), la aplicación inicia la actividad DetailsActivity para mostrar el contenido del elemento.

Aquí está la DetailsActivity, que simplemente integra el DetailsFragment para mostrar el resumen de la obra seleccionada cuando la orientación de la pantalla sea vertical:

public static class DetailsActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line with the list so we don't need this activity.
            finish();
            return;
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
        }
    }
}

Recuerda que esta actividad finaliza automáticamente si la configuración de pantalla es horizontal, de modo que se pueda reanudar la actividad principal y mostrar el DetailsFragment junto con el TitlesFragment. Esto puede ocurrir si el usuario inicia la DetailsActivity mientras la orientación de la pantalla sea vertical, pero luego se aplica una rotación a la posición horizontal (con lo cual se reinicia la actividad actual).

Para obtener más ejemplos sobre el uso de fragmentos (y todos los archivos de origen para este ejemplo), consulta la aplicación de ejemplo de Demostraciones de API disponible en ApiDemos (puedes descargarla en el componente Ejemplos del SDK).

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)