Diseño de Interfaz de Usuario Android: Trabajando con Fragments
() translation by (you can also view the original English article)



La nueva Fragment API para Android, introduce Android 3.0, que permite interfaces de usuario dinámicas. En este tutorial, aprenda a cómo convertir un ListView a dos pantallas de un flujo de trabajo WebView en una sola pantalla diseñada para pantallas grandes, tales como las que encuentra en las tablets.
Ciertos aspectos de las aplicaciones o técnicas utilizadas en este tutorial han cambiado desde que fueron publicadas originalmente. Esto podría hacerlo un poco más difícil de seguir. Por lo que le recomendamos que mire los tutoriales más recientes sobre el mismo tema:
El ritmo de este tutorial va a ser más rápido que algunos de nuestros tutoriales para principiantes, tal vez tenga que revisar algunos de los otros tutoriales de Android en este sitio o incluso en la referencia Android SDK si aún no se ha familiarizado con algunos de los conceptos y clases básicas de Android que discutimos en este tutorial. La muestra de código final que acompaña este tutorial está disponibles para descargar como código abierto desde el alojamiento de código de Google.
Introducción a los Fragments
Antes que comencemos, vamos a definir qué es un Fragment, en un alto nivel. Un Fragment es, por lo general, una parte de la interfaz de usuario con su propio ciclo de vida. Si eso le suena parecido a un Activity, es porque es así; es parecido a un Activity. Sin embargo, un Fragment, es diferente de un Activity en que un Fragment debe existir dentro de un Activity. Un Fragment, no tiene que ser acoplado con el mismo Activity cada vez que éste es inicializado, lo cual le da algo de flexibilidad. Además, como un Activity, un Fragment no necesita contener cualquier interfaz de usuario.
Paso 0: Comenzar
Este tutorial supone que usted empezará donde nuestro tutorial ListView quedó. Puede descargar ese código e incorporarlo desde ahí, aunque tendrá algunas tareas para hacer sin asistencia, o puede descargar el código para este tutorial y seguirnos.
Paso 1: Rediseñando las Pantallas
Las siguientes figuras illustran el flujo de trabajo que existe de nuestra aplicación para leer artículos de Mobiletuts+ (el tutorial ListView) antes un diseño Fragment se consideró y se aplicó:



Este flujo de trabajo funciona bien en los teléfonos con pantallas relativamente pequeñas. Sin embargo, en una pantalla grande, como de 10” (pulgadas) de un Motorola Xoom, que hay mucho espacio desperdiciado en la pantalla ListView. La pantalla WebView se ve bien, pero es un poco aburrido.
Aquí es donde los Fragments vienen a jugar su papel: en las pantallas grandes, podríamos proporcionar una interfaz de usuario más efectiva si podríamos mostrar el ListView en la misma pantalla como en el WebView. Cuando el usuario hace clic en un elemento ListView en específico en el lado izquierdo del "panel", la WebView en la parte derecha se actualiza para mostrar el contenido apropiado. Este tipo de flujo de trabajo es usado frecuentemente en correo electrónico o en lectores de documentos. La siguiente figura ilustra tal rediseño:



Paso 2: Convirtiendo un diseño con basado en Fragments
Ahora que sabemos como es que será diseñada el nuevo flujo de trabajo de la pantalla, también sabemos que las dos activities en curso necesitarán ser convertidas a fragments. Haremos la conversión en varios pasos. El primer paso involucra dejar las pantallas visualmente sin cambiar, pero modificando cada pantalla para usar un fragment. Un fragment va a contener el ListView actual y otro contendrá el WebView. Luego, cambiaremos a una sola implementación de pantalla, la cual implica que hay que modificar mensajes entre los activities-cambiados-fragments de los ListView y el WebView.
Primero, cambie el Project Build Target de su apicación a Android 3.0. Para hacer esto desde la parte interior de Eclipse, pulse el clic-derecho sobre el proyecto y escoja Propiedades. Navegue hasta la sección Android y marque la casilla junto a Android 3.0. No estamos usando ninguna API de Google, por lo que la versión Android Opne Source Projec es suficiente. Después, haga clic sobre el botón OK.
Ahora tendrá acceso a las nuevas APIs, incluyendo la API Fragments.
Nota: En un tutorial en el futuro, hablaremos sobre usar la nueva capa de compatibilidad para que permita a nuevas tecnologías como Fragment API, trabajar en versiones anteriores de Android. Pero, por ahora, requieren un dispositivo con Android 3.0, Honeycomb.
Paso 3: Creando las clases Fragment
Crear dos clases nuevas de Java para representar a los dos fragments: las pantallas ListView y WebView. Nombrarlas TutlListFragment y TutViewerFragment. TutlListFragment extenderá la clase ListFragment y TutViewerFragment solamente extenderá la clase Fragment.
Dentro de la clase TutlListFragment, necesitamos anular dos métodos: onListItemClick() y onCreate(). Los contenidos de estos métodos debería de ser familiares para usted, ya que ellos corresponden a los que teníamos anteriormente en la clase TutListActivity. Esto cambiará dentro de poco, pero aún no. Aquí está una lista de las clases TutListFragment, por ahora:
1 |
|
2 |
@Override
|
3 |
public void onListItemClick(ListView l, View v, int position, long id) { |
4 |
String[] links = getResources().getStringArray(R.array.tut_links); |
5 |
|
6 |
String content = links[position]; |
7 |
Intent showContent = new Intent(getActivity().getApplicationContext(), |
8 |
TutViewerActivity.class); |
9 |
showContent.setData(Uri.parse(content)); |
10 |
startActivity(showContent); |
11 |
}
|
12 |
|
13 |
@Override
|
14 |
public void onCreate(Bundle savedInstanceState) { |
15 |
super.onCreate(savedInstanceState); |
16 |
setListAdapter(ArrayAdapter.createFromResource(getActivity() |
17 |
.getApplicationContext(), R.array.tut_titles, |
18 |
R.layout.list_item)); |
19 |
}
|
La clase TutViewerFragment es un poco más sencilla. Usamos el hecho de que sabemos (ahora) que fragment está ejecutándose bajo el mismo activity utilizado y agarra la instancia de dato directamente desde el interior de la clase Fragment. Añada un método override para el método onCreateView(). Estos métodos, ahora debería de lucir así:
1 |
|
2 |
@Override
|
3 |
public View onCreateView(LayoutInflater inflater, ViewGroup container, |
4 |
Bundle savedInstanceState) { |
5 |
Intent launchingIntent = getActivity().getIntent(); |
6 |
String content = launchingIntent.getData().toString(); |
7 |
|
8 |
WebView viewer = (WebView) inflater.inflate(R.layout.tut_view, container, false); |
9 |
viewer.loadUrl(content); |
10 |
|
11 |
return viewer; |
12 |
}
|
La habilidad para tener acceso a la instancia activity es muy útil, pero creará un problema más adelante. ¿Qué pasa si este fragment está en la pantalla con el list fragment? En ese escenario, no habrá ninguna ejecución Intent para conseguir la URL. De manera similar, en TutListFragment, ejecutaremos un nuevo Activity directamente siempre que el usuario haga clic sobre un ítem en la lista. ¿Qué pasa si el TutViewFragment existió dentro del mismo activity? Si es así, ejecutar un nuevo activity no tendría sentido. Regresaremos para resolver estos problemas más tarde en este tutorial.
Paso 4: Añadiendo los Fragment Layout Resources
Ahora cree un nuevo archivo layout llamado tutlist_fragment.xml para representar el Fragment que contiene la lista de los artículos. Un Fragment layout resource usa la etiqueta y hace la referencia a la clase Fragment que usted creó.
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<fragment
|
4 |
xmlns:android="http://schemas.android.com/apk/res/android" |
5 |
android:name="com.mamlambo.tutorial.tutlist.TutListFragment" |
6 |
android:layout_width="match_parent" |
7 |
android:layout_height="match_parent" |
8 |
android:id="@+id/tutlist_fragment"> |
9 |
</fragment>
|
Después, creamos un archivo layout similar llamado tutview_fragment.xml.
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<fragment
|
4 |
xmlns:android="http://schemas.android.com/apk/res/android" |
5 |
android:name="com.mamlambo.tutorial.tutlist.TutViewerFragment" |
6 |
android:layout_width="match_parent" |
7 |
android:layout_height="match_parent" |
8 |
android:id="@+id/tutview_fragment"> |
9 |
</fragment>
|
Paso 5: Actualizando las clases Activity
Las clases TutListActivity y TutViewerActivity, ahora deben ser actualizadas. La clase TutListActivity tiene un solo método, onCreate() que ahora debería de ser actualizado para cargar el adecuado Fragment layout resource que usted creó en el paso anterior, así como este:
1 |
|
2 |
@Override
|
3 |
public void onCreate(Bundle savedInstanceState) { |
4 |
super.onCreate(savedInstanceState); |
5 |
|
6 |
setContentView(R.layout.tutlist_fragment); |
7 |
}
|
Además, note que, la clase TutListActivity debería heredar de la clase Activity y no de la clase ListActivity.
La clase TutViewerActivity, requiere un cambio similar. Su método onCreate() ahora debería de lucir así:
1 |
|
2 |
@Override
|
3 |
public void onCreate(Bundle savedInstanceState) { |
4 |
super.onCreate(savedInstanceState); |
5 |
setContentView(R.layout.tutview_fragment); |
6 |
}
|
Paso 6: Evaluando su Progreso
Trate de ejecutar la aplicación ahora. Notará que hace exactamente lo que solía hacer. Nada emocionante. Sin embargo, la interfaz completa de usuario ahora está lista usando fragments. Esto permitirá el siguiente cambio que usted necesita hacer para ir sin problemas ya que añadimos un nuevo layout para combinar los dos fragments para visualizaciones grandes para mostrar al usuario en una sola pantalla. Sin embargo, como habrá notado, la comunicación entre los fragments está manejada idénticamente a como nos comunicaríamos entre activities. De hecho, usamos la información de cada fragment del activity que fue acoplado sin cambios. Esto no será el caso cuando tengamos una sola activity que contiene y controla los dos fragments. Primero, arreglemos esto.
Paso 7: Cambiando la comunicación para TutListFragment
Como aprendió en el paso 3, cuando ejecuta directamente un activity desde el interior del objeto TutListFragment ya no tiene ningún sentido. La interfaz de usuario de la WebView puede, de hecho, ser parte del mismo activity como la List —de cualquier manera ese es nuestro plan para las pantallas grandes. En ese caso, queremos actualizar la URL de la WebView en el segundo fragment.
Para hacer este cambio, necesitamos hacer varias cosas. Primero, vamos a hacer los fragments independientes del activity en el cual residen. Para hacer esto, agregamos una interfaz listener a la clase TutlistFragment, así:
1 |
|
2 |
public interface OnTutSelectedListener { |
3 |
public void onTutSelected(Uri tutUri); |
4 |
}
|
Y luego, lo activamos por medio de la actualización del método onListItemClickListener() de la siguiente manera:
1 |
|
2 |
@Override
|
3 |
public void onListItemClick(ListView l, View v, int position, long id) { |
4 |
String[] links = getResources().getStringArray(R.array.tut_links); |
5 |
|
6 |
String content = links[position]; |
7 |
tutSelectedListener.onTutSelected(Uri.parse(content)); |
8 |
}
|
Después, tenemos que implementar la clase TutListActivity y la interfaz OnTutsSelectedListener, de esta manera:
1 |
|
2 |
public class TutListActivity extends Activity implements |
3 |
TutListFragment.OnTutSelectedListener { |
4 |
...
|
5 |
@Override
|
6 |
public void onTutSelected(Uri tutUri) { |
7 |
Intent showContent = new Intent(getApplicationContext(), |
8 |
TutViewerActivity.class); |
9 |
showContent.setData(tutUri); |
10 |
startActivity(showContent); |
11 |
}
|
Ahora tenemos la funcionalidad separada entre el fragment, el cual controla las acciones de interfaz de los usuarios y la activity, la cual puede ser controlada, pasando los datos en la siguiente activity. Modificaremos el método onTutSelected() más tarde para decidir si o no ejecutamos una nueva instancia Activity o actualizamos la instancia existente.
Paso 8: Cambiando la comunicación para TutViewerFragment
Ahora vamos a mover nuestra atención hacia la clase TutViewerFragment, la cual, también, necesita ser actualizada. En lugar de cuestionar la ejecución intent para averiguar cual URL cargar, el fragment esperará a que le digan cual es la URL para cargar. En esta forma, podemos actualizar directamente la WebView y no recrear el fragment con cada carga.
Primero, modifique la clase TutViewerFragment para incluir un nuevo método llamado updateUrl():
1 |
|
2 |
public void updateUrl(String newUrl) { |
3 |
if (viewer != null) { |
4 |
viewer.loadUrl(newUrl); |
5 |
}
|
6 |
}
|
Después, elimine todas las funcionalidades del método onCreateView() a excepción de la llamada inflate(). Sobre la clase TutViewerActivity, añada de nuevo la funcionalidad para recuperar el Intent y luego llame al método updateUrl(), de la siguiente manera:
1 |
|
2 |
@Override
|
3 |
public void onCreate(Bundle savedInstanceState) { |
4 |
super.onCreate(savedInstanceState); |
5 |
setContentView(R.layout.tutview_fragment); |
6 |
|
7 |
Intent launchingIntent = getIntent(); |
8 |
String content = launchingIntent.getData().toString(); |
9 |
|
10 |
TutViewerFragment viewer = (TutViewerFragment) getFragmentManager() |
11 |
.findFragmentById(R.id.tutview_fragment); |
12 |
|
13 |
viewer.updateUrl(content); |
14 |
}
|
En este punto, el funcionamiento de la aplicación queda sin cambios. Los fragmets, sin embargo, ahora pueden existir dentro del mismo Activity o separados sin más cambios en los códigos.
Paso 9: Añadiendo un Dual Fragment Layout
Ahora vamos a crear un layout con ambos fragments, pasa usarlos en ciertas situaciones. En la carpeta del layout (que es posible que la necesite crear) añada una copia del archivo tutlist_fragment.xml. Esto proporcionará un layout diferente para la orientación panorámica en cualquier pantalla apaisada. El modo retrato, quedará sin cambios. Edite el archivo para que se parezca al siguiente layout con los dos fragments.
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<LinearLayout
|
4 |
xmlns:android="http://schemas.android.com/apk/res/android" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="match_parent" |
7 |
android:orientation="horizontal"> |
8 |
<fragment
|
9 |
android:name="com.mamlambo.tutorial.tutlist.TutListFragment" |
10 |
android:layout_width="0dp" |
11 |
android:layout_height="match_parent" |
12 |
android:id="@+id/tutlist_fragment" |
13 |
android:layout_weight="45"> |
14 |
</fragment>
|
15 |
<fragment
|
16 |
android:name="com.mamlambo.tutorial.tutlist.TutViewerFragment" |
17 |
android:layout_width="0dp" |
18 |
android:layout_height="match_parent" |
19 |
android:id="@+id/tutview_fragment" |
20 |
android:layout_weight="55"> |
21 |
</fragment>
|
22 |
</LinearLayout>
|
Esto dividirá la pantalla horizontalmente entre dos fragments.
Paso 10: Añadiendo una Opción Dinámica
Ahora podemos añadir algo de lógica simple a la aplicación para escoger entre ejecutar una nueva activity (los dos flujos de trabajo de pantalla) y actualizar un fragment existente (una pantalla).
Para hacer esto, actualice el método onTutSelecte() de la clase TutListActivity como sigue a continuación:
1 |
|
2 |
@Override
|
3 |
public void onTutSelected(String tutUrl) { |
4 |
TutViewerFragment viewer = (TutViewerFragment) getFragmentManager() |
5 |
.findFragmentById(R.id.tutview_fragment); |
6 |
|
7 |
if (viewer == null || !viewer.isInLayout()) { |
8 |
Intent showContent = new Intent(getApplicationContext(), |
9 |
TutViewerActivity.class); |
10 |
showContent.setData(Uri.parse(tutUrl)); |
11 |
startActivity(showContent); |
12 |
} else { |
13 |
viewer.updateUrl(tutUrl); |
14 |
}
|
15 |
}
|
Todo lo que esto hace es agarrar un fragment y revisar para ver si es parte del layout existente para el Activity. Si no, el viewer activity es ejecutado, de lo contrario, en su lugar el fragment es actualizado.
Paso 11: Ejecutando la nueva App Fragment-Aware
En este punto, la aplicación funcionaría en dos modos diferentes: retrato sin cambios, mientras que el modo panorama muestra el ListView a la izquierda del WebView. Hay varias mejoras que podrían haberse hecho en este punto, pero aún están retocando, optimizando y una variedad de partes y, principalmente, para perfeccionar. Por ejemplo, si usted está en el modo retrato del WebView y rota la pantalla, el resultado aún es la pantalla WebView. Tiene que volver a presionar para obtener las dos vistas. La perfección está más allá de este tutorial, pero puede ver como con un uso juicioso de layouts y un poco de lógica de activity, usted puede lograr potentes pero flexibles flujos de trabajo de pantalla para una variedad de pantallas y dispositivos.



En conclusión
El fragmento API ayuda a organizar los componentes de la interfaz de usuario para que se puedan volver a utilizar a través de los activities. En esta forma, una aplicación puede ser dinámicamente ajustada a su flujo de trabajo y a las interfaces de usuario con, relativamente, poco código. Además, ha visto que una aplicación que se basa en fragments es más fácil de organizar. Incluso mejor, como cualquier aplicación puede aprovechar los fragments que están disponibles por medio de una biblioteca de compatibilidad proporcionada por Google que es compatible en lo que respecta a Android 1.6
Ahora salga y aplique fragment a sus aplicaciones de interfaz de usuarios y haga interfaces de usuarios asombrosas para cada tamaño de pantalla y para cada forma.
Sobre los Autores
Desarrolladores de Celulares; Lauren Darcey y Shane Conder son coautores de varios libros sobre el desarrollo en Android: un libro de programación a fondo titulado: Desarrollo de Aplicaciones Inalámbricas de Android y Sams Aprenda usted mismo a Desarrollar Aplicaciones para Android en 24 horas, segunda edición. Cuando no escriben, ellos pasan su tiempo desarrollando programas para celulares en sus empresas y proporcionando servicios de consultoría. Pueden ser localizado a través de correo electrónico: androidwirelessdev+mt@gmail.com o por medio de su blog en androidbook.blogspot.com y en Twitter @androidwireless.
¿Necesita más ayuda escribiendo aplicaciones de Android? ¡Revise nuestros últimos libros y recursos!
