¿Qué es un fragmento?
onAttach: Es invocado cuando el fragmento ha sido asociado a la actividad anfitriona.
onActiviyCreated: Se ejecuta cuando la actividad anfitriona ya ha terminado la ejecución de su metodo onCreate().
onCreate: Este método es llamado cuando el fragmento se esta creando. En el puedes inicializar todos los componentes que deseas guardar si el fragmento fue pausado o detenido.
onCreateView: Se llama cuando el fragmento será dibujado por primera vez en la interfaz de usuario. En este método crearemos el view que representa al fragmento para retornarlo hacia la actividad.
onStart: Se llama cuando el fragmento esta visible ante el usuario. Obviamente depende del método onStart() de la actividad para saber si la actividad se esta mostrando.
onResume: Es ejecutado cuando el fragmento esta activo e interactuando con el usuario. Esta situacion depende de la que actividad anfitriona este primero en su estado Resumed.
onStop: Se llama cuando un fragmento ya no es visible para el usuario debido a que la actividad anfitriona esta detenida o porque dentro de la actividad se esta gestionando una operación de fragmentos.
onPause: Al igual que las actividades, onPause se ejecuta cuando se detecta que el usuario dirigió el foco por fuera del fragmento.
onDestroyView: Este método es llamado cuando la jerarquía de views a la cual ha sido asociado el fragmento ha sido destruida.
onDetach: Se llama cuando el fragmento ya no esta asociado a la actividad anfitriona.
Creando un fragmento embebido
public static class FragmentoEjemplo extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragmento_ejemplo, container, false);
}
}
El método onCreateView() recibe como parámetro un objeto de tipo LayoutInflater, el cual es proveído por la clase anfitriona.
Esta clase es la encargada de inflar el código Java a través del método inflate(). Este recibe como parámetros el recurso xml del layout, el contenedor(en este caso el view de la actividad anfitriona) donde será insertado y una bandera indicando si el view que se producirá debe adherirse al contenedor.
Como se ve, hemos usado al archivo fragmento_ejemplo.xml como recurso, el parámetro container que apunta a la actividad anfitriona y false para indicar que no indicar que no deseamos comprometer el view del fragmento.
¿Como añadir el fragmento a la actividad?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.herprogramacion.fragmentos.FragmentoEjemplo"
android:id="@+id/ejemplo"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
El código anterior muestra un nodo <fragment> embebido como hijo en el LinearLayout de nuestra actividad. Es importante usar un atributo id para el fragmento, ya que esto permitirá diferenciarlo de otros fragmentos a la hora de hacer la búsqueda de alguno en especial. De esa forma al ejecutar el proyecto el fragmento aparecerá automáticamente.
La segunda forma se trata de insertar el fragmento en tiempo de ejecución. Lo que quiere decir que no usaremos el nodo <fragment>, si no que usaremos el estilo programático para añadir por código Java el fragmento a la actividad.
Embeber un fragmento dentro de una actividad
Pasos para embeber un fragmento en Android Studio
Paso 1: Creación de fragmento
package TUPAQUETE.APLICACION;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
*
* A simple {@link Fragment} subclass.
*
public class CountFragment extends Fragment {
public CountFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_count, container, false);
}
}
Como ves, se ha creado el método onCreateView() de forma automática asignando como recurso al layout fragment_count.xml que se autogeneró en nuestro proyecto.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="TUPAQUETE.APLICACION.CountFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
Paso 2: Mover todo el código de la actividad al fragmento
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="TUPAQUETE.APLICACION.CountFragment">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/main_editText"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:hint="@string/hint" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/main_button"
android:layout_below="@+id/main_editText"
android:layout_centerHorizontal="true"
android:layout_marginTop="41dp"
android:text="@string/button" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:id="@+id/main_textview"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:layout_below="@+id/main_button"
android:layout_marginTop="41dp" />
</RelativeLayout>
Ahora cortaremos todo el código Java del metodo onCreate() de la actividad al método onCreateView() del fragmento. Al pegar el código, Android Studio te permitirá importar automáticamente todas las dependencia necesarias para mantener la funcionalidad.
boton = (Button)findViewById(R.id.main_button);
edit = (EditText)findViewById(R.id.main_editText);
text = (TextView)findViewById(R.id.main_textview);
Muy bien, al parecer nuestro método findViewById() no funciona en el contexto del fragmento. Esto se debe a que el único que puede referenciar a todos los Views de un un fragmento es el View padre del fragmento. Dicho view es obtenido cuando se infla el layout.
Para tener una referencia a este simplemente crearemos una instancia de tipo View y asignaremos el resultado al inflar el código XML. Luego invocaremos el método findViewById() desde la nueva instancia. Veamos
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_count, container, false);
boton = (Button)view.findViewById(R.id.main_button);
edit = (EditText)view.findViewById(R.id.main_editText);
text = (TextView)view.findViewById(R.id.main_textview);
De este modo ya podemos obtener los views que hay en el layout del fragmento y retornar la variable view al final del método onCreateView(). El código completo del fragmento sería este:
package TUPAQUETE.APLICACION;
import android.app.Activity;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
*
* A simple {@link Fragment} subclass.
*
public class CountFragment extends Fragment {
private Button boton;
private EditText edit;
private TextView text;
public CountFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_count, container, false);
boton = (Button)view.findViewById(R.id.main_button);
edit = (EditText)view.findViewById(R.id.main_editText);
text = (TextView)view.findViewById(R.id.main_textview);
boton.setOnClickListener( new View.OnClickListener() {
public void onClick(View view){
String mensaje = edit.getText().toString();
text.setText(String.valueOf(mensaje.length()));
}
});
return view;
}
}
Paso 3: Insertar el fragmento en el layout de la actividad
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MyActivity">
<fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="herprogramacion.test.CountFragment"
android:id="@+id/fragment"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
class="herprogramacion.test.CountFragment"
tools:layout="@layout/fragment_count" />
</RelativeLayout>
Si observas bien, el atributo "tools:layout" ya tiene asignado al layout fragment_count.
Al igual que los demás views, un fragmento debe tener definido un identificador id para diferenciarse de los demás y poder encontrarlo a través de búsquedas directas. En este caso el fragmento esta denominado por el identificador "fragment".
Paso 4: Ejecuta y comprueba
Creando un fragmento en tiempo de ejecución
¡Show me the code!
Pasos para añadir un fragmento en tiempo de ejecución
Paso 1: Obtener una instancia del FragmentManager
//Paso 1: Obtener la instancia del administrador de fragmentos
FragmentManager fragmentManager = getFragmentManager();
Paso 2: Crear la instancia de la transacción
//Paso 2: Crear una nueva transacción
FragmentTransaction transaction = fragmentManager.beginTransaction();
Paso 3: Crear un nuevo fragmento y añadirlo a la actividad
//Paso 3: Crear un nuevo fragmento y añadirlo
CountFragment fragment = new CountFragment();
transaction.add(R.id.contenedor, fragment);
Como ves, el método add() recibe dos parámetros. El primero es el identificador del contenedor donde insertaremos el fragmento. En este caso es el RelativeLayout de nuestra actividad, al cual le asigné el id "contenedor".
El segundo parámetro es la instancia del fragmento que queremos añadir.
Paso 4: Confirmar los cambios
//Paso 4: Confirmar el cambio
transaction.commit();
El código final de nuestra actividad tendría la siguiente estructura:
package herprogramacion.test;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MyActivity extends Activity {
private Button add_fragment ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
//Obteniendo la instancia del botón add_fragment
add_fragment = (Button)findViewById(R.id.add_fragment);
//Seteando la escucha del botón
add_fragment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Paso 1: Obtener la instancia del administrador de fragmentos
FragmentManager fragmentManager = getFragmentManager();
//Paso 2: Crear una nueva transacción
FragmentTransaction transaction = fragmentManager.beginTransaction();
//Paso 3: Crear un nuevo fragmento y añadirlo
CountFragment fragment = new CountFragment();
transaction.add(R.id.contenedor, fragment);
//Paso 4: Confirmar el cambio
transaction.commit();
}
});
}
}
Pero aun falta un detalle adicional. Si ejecutásemos la aplicación de la forma en que se encuentra, el fragmento aparecerá sin alineación establecida con respecto al botón. Tal vez aparezca superpuesto, perdiendo todo el sentido de la estética. Por esa razón, añadiremos los siguientes parámetros programáticamente al View del fragmento:
Su borde superior este por debajo del borde inferior del botón.
Su margen superior tiene 41dp con respecto a los otros elementos del RelativeLayout.
//Nuevos parametros para el view del fragmento
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
//Nueva Regla: EL fragmento estara debajo del boton add_fragment
params.addRule(RelativeLayout.BELOW, R.id.add_fragment);
//Margenes: top:41dp
params.setMargins(0,41,0,0);
//Setear los parametros al view
view.setLayoutParams(params);
Lo primero que debemos tener en cuenta es que los atributos de un view dentro de un RelativeLayout son representados por la clase LayoutParams. Si tuviésemos un ViewGroup distinto a RelativeLayout también se usaría la misma clase LayoutParams en su paquete correspondiente.
Si nos ubicamos en la primera instrucción veremos una nueva instancia que recibe en su constructor el ancho y el alto del view. Para ello usamos las constantes MATCH_PARENT para indicar un autoajuste al tamaño del padre.
Luego de ello añadiremos una nueva regla de alineación.
Se le llama reglas a todas las condiciones referentes a la ubicación de los views que debe interpretar un RelativeLa