Diseño de Interfaz de Usuario Android: Tabla de Composiciones
Spanish (Español) translation by Rodney Martinez (you can also view the original English article)
Table layouts, puede user utilizado para mostrar datos de forma tabular o bien, alineando los contenidos en la pantalla en una forma similar a una tabla HTML en una página web. Aprenda cómo crearlas con los archivos layout XML y a través del código.
Entender los Layouts es importante para el buen diseño de la aplicación Android. En este tutorial, aprenderá todo sobre las tablas layouts, las cuales organizan los controles de la interfaz de usuario, o widgets, en la pantalla, prácticamente en filas y columnas definidas. Cuando se usan correctamente, los tablas layouts pueden ser potentes paradigmas sobre las que pueden ser diseñadas sus pantallas o mostrar los datos de forma tabular.
¿Qué es una Table Layout?
Una table layout es, exactamente, lo que se podría esperar: una cuadrícula hecha de filas y columnas, en donde una celda puede mostrar un control vista. Desde la perspectiva de diseño de una interfaz de usuario, una TableLayout está compuesta de controles TableRow —uno para cada fila en su tabla. Los contenidos de una TableRow son simplemente controles view que lo irán en cada "celda" de la tabla.
La apariencia de una TableLayout está regida por varias reglas adicionales. Primero, el número de columnas de toda la tabla coincide con el número de columnas en la fila con la mayoría de las columnas. Segundo, el ancho de cada columna está definido como el ancho del contenido más amplio en la columna. Las filas child del TableLayout y las celdas de los atributos layout_width siempre están en MATCH_PARENT -- aunque no se pueden poner en un archivo XML, el valor actual no puede ser anulado. El parámetro layout_height de la TableLayout de una celda puede ser definido, sin embargo, un atributo TableRow para layout_height está siempre WRAP_CONTENT. Las celdas pueden abarcar columnas, pero no filas. Esto se hace a través del atributo layout_span de la vista child de una TableRow. Una celda es una sola vista child dentro de una TableRow. Si quiere una celda más compleja con múltiples vistas, use una vista layout para encapsular las otras vistas.
Dicho eso, algunas reglas pueden ser modificadas. Las columnas pueden ser marcadas como estirables, lo que significa que el ancho se puede expandir al tamaño del contenedor parent. También, las columnas pueden ser marcadas como encogibles, lo que significa que pueden ser reducidas en anchura para que la fila entera encaje en el lugar proporcionado por el contenedor parent.
Para la documentación completa para la table layouts, vea la documentación Android SDK para la clase TableLayout. El atributo XML asociado para usar en XML resource, también, está definido en la documentación.
Diseñando un Simple Table Layout
Los layouts, se explican mejor con ejemplos, y los table layout no son diferentes. Digamos que queremos diseñar una pantalla que muestra el pronóstico del tiempo ampliado. Una table layout podría ser una buena opción para organizar esta información:
- En la primer TableRow, podemos mostrar un título para la pantalla.
- En la segunda TableRow, podemos mostrar las fechas en un formato familiar como el de un calendario.
- En la tercera TableRow, podemos mostrar una información para la temperatura Más Alta Diariamente.
- En la cuarta TableRow, podemos mostrar una información de temperatura Diaria Baja.
- En la quinta TableRow, podemos mostrar gráficos para identificar las condiciones del clima, tales como lluvia, nieve, sol, nublado con una probabilidad de pelotas.
La primera figura muestra un vistazo en la tabla dentro del editor layout:


Definiendo un XML Layour Resource con un Table Layout
La manera más conveniente y sostenible de diseñar una aplicación de interfaz de usuario es por medio de la creación de XML layout resources. Este método simplifica mucho el proceso de diseño UI, moviéndose de la creación static y layout de los controles de interfaz de usuario y la definición de los controles de los atributos, hacia el XML, en lugar de las letras de código.
XML layout resource, deben ser guardados en la jerarquía del directorio del proyecto: /res/layout. Vamos a echar un vistazo a los table layout presentados en la sección anterior. Este archivo layout resource, nombrado convenientemente como /res/layout/table.xml, está definido en XML como sigue:
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<TableLayout
|
4 |
xmlns:android="http://schemas.android.com/apk/res/android" |
5 |
android:id="@+id/tableLayout1" |
6 |
android:layout_width="match_parent" |
7 |
android:layout_height="match_parent" |
8 |
android:shrinkColumns="*" |
9 |
android:stretchColumns="*"> |
10 |
<TableRow
|
11 |
android:id="@+id/tableRow4" |
12 |
android:layout_height="wrap_content" |
13 |
android:layout_width="match_parent" |
14 |
android:gravity="center_horizontal"> |
15 |
<TextView
|
16 |
android:id="@+id/textView9" |
17 |
android:layout_width="match_parent" |
18 |
android:layout_height="wrap_content" |
19 |
android:textStyle="bold" |
20 |
android:typeface="serif" |
21 |
android:textSize="18dp" |
22 |
android:text="Weather Table" |
23 |
android:gravity="center" |
24 |
android:layout_span="6"></TextView> |
25 |
</TableRow>
|
26 |
<TableRow
|
27 |
android:id="@+id/tableRow1" |
28 |
android:layout_height="wrap_content" |
29 |
android:layout_width="match_parent"> |
30 |
<TextView
|
31 |
android:id="@+id/TextView04" |
32 |
android:text=""></TextView> |
33 |
<TextView
|
34 |
android:id="@+id/TextView04" |
35 |
android:text="Feb 7" |
36 |
android:textStyle="bold" |
37 |
android:typeface="serif"></TextView> |
38 |
<TextView
|
39 |
android:id="@+id/TextView03" |
40 |
android:text="Feb 8" |
41 |
android:textStyle="bold" |
42 |
android:typeface="serif"></TextView> |
43 |
<TextView
|
44 |
android:id="@+id/TextView02" |
45 |
android:text="Feb 9" |
46 |
android:textStyle="bold" |
47 |
android:typeface="serif"></TextView> |
48 |
<TextView
|
49 |
android:id="@+id/TextView01" |
50 |
android:text="Feb 10" |
51 |
android:textStyle="bold" |
52 |
android:typeface="serif"></TextView> |
53 |
<TextView
|
54 |
android:text="Feb 11" |
55 |
android:id="@+id/textView1" |
56 |
android:textStyle="bold" |
57 |
android:typeface="serif"></TextView> |
58 |
</TableRow>
|
59 |
<TableRow
|
60 |
android:layout_height="wrap_content" |
61 |
android:id="@+id/tableRow2" |
62 |
android:layout_width="match_parent"> |
63 |
<TextView
|
64 |
android:text="Day High" |
65 |
android:id="@+id/textView2" |
66 |
android:textStyle="bold"></TextView> |
67 |
<TextView
|
68 |
android:id="@+id/textView3" |
69 |
android:text="28°F" |
70 |
android:gravity="center_horizontal"></TextView> |
71 |
<TextView
|
72 |
android:text="26°F" |
73 |
android:id="@+id/textView4" |
74 |
android:gravity="center_horizontal"></TextView> |
75 |
<TextView
|
76 |
android:text="23°F" |
77 |
android:id="@+id/textView5" |
78 |
android:gravity="center_horizontal"></TextView> |
79 |
<TextView
|
80 |
android:text="17°F" |
81 |
android:id="@+id/textView6" |
82 |
android:gravity="center_horizontal"></TextView> |
83 |
<TextView
|
84 |
android:text="19°F" |
85 |
android:id="@+id/textView7" |
86 |
android:gravity="center_horizontal"></TextView> |
87 |
</TableRow>
|
88 |
<TableRow
|
89 |
android:layout_height="wrap_content" |
90 |
android:id="@+id/tableRow2" |
91 |
android:layout_width="match_parent"> |
92 |
<TextView
|
93 |
android:text="Day Low" |
94 |
android:id="@+id/textView2" |
95 |
android:textStyle="bold"></TextView> |
96 |
<TextView
|
97 |
android:text="15°F" |
98 |
android:id="@+id/textView3" |
99 |
android:gravity="center_horizontal"></TextView> |
100 |
<TextView
|
101 |
android:text="14°F" |
102 |
android:id="@+id/textView4" |
103 |
android:gravity="center_horizontal"></TextView> |
104 |
<TextView
|
105 |
android:text="3°F" |
106 |
android:id="@+id/textView5" |
107 |
android:gravity="center_horizontal"></TextView> |
108 |
<TextView
|
109 |
android:text="5°F" |
110 |
android:id="@+id/textView6" |
111 |
android:gravity="center_horizontal"></TextView> |
112 |
<TextView
|
113 |
android:text="6°F" |
114 |
android:id="@+id/textView7" |
115 |
android:gravity="center_horizontal"></TextView> |
116 |
</TableRow>
|
117 |
<TableRow
|
118 |
android:id="@+id/tableRow3" |
119 |
android:layout_height="wrap_content" |
120 |
android:layout_width="match_parent" |
121 |
android:gravity="center"> |
122 |
<TextView
|
123 |
android:id="@+id/textView8" |
124 |
android:text="Conditions" |
125 |
android:textStyle="bold"></TextView> |
126 |
<ImageView
|
127 |
android:id="@+id/imageView1" |
128 |
android:src="@drawable/hot"></ImageView> |
129 |
<ImageView
|
130 |
android:id="@+id/imageView2" |
131 |
android:src="@drawable/pt_cloud"></ImageView> |
132 |
<ImageView
|
133 |
android:id="@+id/imageView3" |
134 |
android:src="@drawable/snow"></ImageView> |
135 |
<ImageView
|
136 |
android:id="@+id/imageView4" |
137 |
android:src="@drawable/lt_snow"></ImageView> |
138 |
<ImageView
|
139 |
android:id="@+id/imageView5" |
140 |
android:src="@drawable/pt_sun"></ImageView> |
141 |
</TableRow>
|
142 |
</TableLayout>
|
Recuerde que, desde la parte interna del Activity, solamente una sola línea de código dentro del método onCreate() es necesaria para cargar y mostrar un layout resource en la pantalla.
1 |
|
2 |
setContentView(R.layout.table); |
Esta table layout tiene todas sus columnas ajustadas tanto para reducirse como para estirarse usando un "*" en el valor. Si ciertas columnas deberían reducirse o estirarse, entonces los valores serían separados por una coma (usando 0 como la base para el índice para las columnas).
La tabla ahora luce como se ve en la siguiente captura de pantalla cuando está en modo vertical u horizontal.




Definiendo una Table Layout por medio de programación
También puede crear por medio de programación y configurar table layouts en Java. Esto se hace usando las clases TableLayout y TableRow (android.widget.TableLayout y android.widget.TableRow). Encontrará los únicos parámetros mostrados para cada controle en las clases TableLayout.LayoutParams y TableRow.LayoutParams. Asimismo, los parámetros normales (android.view.ViewGroup.LayoutParams), tales como layout_height y layout_width, así como también los parámetros de los márgenes (ViewGroup.MarginLayoutParams), aún se utilizan en los objetos TableLayout. Para las celdas de las tablas (cualquier View dentro de la TableRow), la anchura siempre es MATCH_PARENT. La altura puede ser definida, pero por defecto será WRAP_CONTENT y no necesita ser especificada.
En vez de cargar un layout resource directamente usando el método setContentView() como se mostró anteriormente, si usted crea un layout por medio de la programación, en lugar de eso de desarrollar la pantalla de contenidos en Java y luego proporcionar un objeto parent layout que contiene los controles de contenidos para mostrar como child views para el método setContentView(). En este caso, su parent layout utilizado sería el table layout creado.
Por ejemplo, el siguiente código ilustra cómo por medio de programación una instancia Activity tiene un parámetro layout TableLayout y reproduce el ejemplo demostrado anteriormente en XML:
1 |
|
2 |
@Override |
3 |
public void onCreate(Bundle savedInstanceState) {
|
4 |
super.onCreate(savedInstanceState); |
5 |
|
6 |
TableLayout table = new TableLayout(this); |
7 |
|
8 |
table.setStretchAllColumns(true); |
9 |
table.setShrinkAllColumns(true); |
10 |
|
11 |
TableRow rowTitle = new TableRow(this); |
12 |
rowTitle.setGravity(Gravity.CENTER_HORIZONTAL); |
13 |
|
14 |
TableRow rowDayLabels = new TableRow(this); |
15 |
TableRow rowHighs = new TableRow(this); |
16 |
TableRow rowLows = new TableRow(this); |
17 |
TableRow rowConditions = new TableRow(this); |
18 |
rowConditions.setGravity(Gravity.CENTER); |
19 |
|
20 |
TextView empty = new TextView(this); |
21 |
|
22 |
// title column/row |
23 |
TextView title = new TextView(this); |
24 |
title.setText("Java Weather Table");
|
25 |
|
26 |
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); |
27 |
title.setGravity(Gravity.CENTER); |
28 |
title.setTypeface(Typeface.SERIF, Typeface.BOLD); |
29 |
|
30 |
TableRow.LayoutParams params = new TableRow.LayoutParams(); |
31 |
params.span = 6; |
32 |
|
33 |
rowTitle.addView(title, params); |
34 |
|
35 |
// labels column |
36 |
TextView highsLabel = new TextView(this); |
37 |
highsLabel.setText("Day High");
|
38 |
highsLabel.setTypeface(Typeface.DEFAULT_BOLD); |
39 |
|
40 |
TextView lowsLabel = new TextView(this); |
41 |
lowsLabel.setText("Day Low");
|
42 |
lowsLabel.setTypeface(Typeface.DEFAULT_BOLD); |
43 |
|
44 |
TextView conditionsLabel = new TextView(this); |
45 |
conditionsLabel.setText("Conditions");
|
46 |
conditionsLabel.setTypeface(Typeface.DEFAULT_BOLD); |
47 |
|
48 |
rowDayLabels.addView(empty); |
49 |
rowHighs.addView(highsLabel); |
50 |
rowLows.addView(lowsLabel); |
51 |
rowConditions.addView(conditionsLabel); |
52 |
|
53 |
// day 1 column |
54 |
TextView day1Label = new TextView(this); |
55 |
day1Label.setText("Feb 7");
|
56 |
day1Label.setTypeface(Typeface.SERIF, Typeface.BOLD); |
57 |
|
58 |
TextView day1High = new TextView(this); |
59 |
day1High.setText("28°F");
|
60 |
day1High.setGravity(Gravity.CENTER_HORIZONTAL); |
61 |
|
62 |
TextView day1Low = new TextView(this); |
63 |
day1Low.setText("15°F");
|
64 |
day1Low.setGravity(Gravity.CENTER_HORIZONTAL); |
65 |
|
66 |
ImageView day1Conditions = new ImageView(this); |
67 |
day1Conditions.setImageResource(R.drawable.hot); |
68 |
|
69 |
rowDayLabels.addView(day1Label); |
70 |
rowHighs.addView(day1High); |
71 |
rowLows.addView(day1Low); |
72 |
rowConditions.addView(day1Conditions); |
73 |
|
74 |
// day2 column |
75 |
TextView day2Label = new TextView(this); |
76 |
day2Label.setText("Feb 8");
|
77 |
day2Label.setTypeface(Typeface.SERIF, Typeface.BOLD); |
78 |
|
79 |
TextView day2High = new TextView(this); |
80 |
day2High.setText("26°F");
|
81 |
day2High.setGravity(Gravity.CENTER_HORIZONTAL); |
82 |
|
83 |
TextView day2Low = new TextView(this); |
84 |
day2Low.setText("14°F");
|
85 |
day2Low.setGravity(Gravity.CENTER_HORIZONTAL); |
86 |
|
87 |
ImageView day2Conditions = new ImageView(this); |
88 |
day2Conditions.setImageResource(R.drawable.pt_cloud); |
89 |
|
90 |
rowDayLabels.addView(day2Label); |
91 |
rowHighs.addView(day2High); |
92 |
rowLows.addView(day2Low); |
93 |
rowConditions.addView(day2Conditions); |
94 |
|
95 |
// day3 column |
96 |
TextView day3Label = new TextView(this); |
97 |
day3Label.setText("Feb 9");
|
98 |
day3Label.setTypeface(Typeface.SERIF, Typeface.BOLD); |
99 |
|
100 |
TextView day3High = new TextView(this); |
101 |
day3High.setText("23°F");
|
102 |
day3High.setGravity(Gravity.CENTER_HORIZONTAL); |
103 |
|
104 |
TextView day3Low = new TextView(this); |
105 |
day3Low.setText("3°F");
|
106 |
day3Low.setGravity(Gravity.CENTER_HORIZONTAL); |
107 |
|
108 |
ImageView day3Conditions = new ImageView(this); |
109 |
day3Conditions.setImageResource(R.drawable.snow); |
110 |
|
111 |
rowDayLabels.addView(day3Label); |
112 |
rowHighs.addView(day3High); |
113 |
rowLows.addView(day3Low); |
114 |
rowConditions.addView(day3Conditions); |
115 |
|
116 |
// day4 column |
117 |
TextView day4Label = new TextView(this); |
118 |
day4Label.setText("Feb 10");
|
119 |
day4Label.setTypeface(Typeface.SERIF, Typeface.BOLD); |
120 |
|
121 |
TextView day4High = new TextView(this); |
122 |
day4High.setText("17°F");
|
123 |
day4High.setGravity(Gravity.CENTER_HORIZONTAL); |
124 |
|
125 |
TextView day4Low = new TextView(this); |
126 |
day4Low.setText("5°F");
|
127 |
day4Low.setGravity(Gravity.CENTER_HORIZONTAL); |
128 |
|
129 |
ImageView day4Conditions = new ImageView(this); |
130 |
day4Conditions.setImageResource(R.drawable.lt_snow); |
131 |
|
132 |
rowDayLabels.addView(day4Label); |
133 |
rowHighs.addView(day4High); |
134 |
rowLows.addView(day4Low); |
135 |
rowConditions.addView(day4Conditions); |
136 |
|
137 |
// day5 column |
138 |
TextView day5Label = new TextView(this); |
139 |
day5Label.setText("Feb 11");
|
140 |
day5Label.setTypeface(Typeface.SERIF, Typeface.BOLD); |
141 |
|
142 |
TextView day5High = new TextView(this); |
143 |
day5High.setText("19°F");
|
144 |
day5High.setGravity(Gravity.CENTER_HORIZONTAL); |
145 |
|
146 |
TextView day5Low = new TextView(this); |
147 |
day5Low.setText("6°F");
|
148 |
day5Low.setGravity(Gravity.CENTER_HORIZONTAL); |
149 |
|
150 |
ImageView day5Conditions = new ImageView(this); |
151 |
day5Conditions.setImageResource(R.drawable.pt_sun); |
152 |
|
153 |
rowDayLabels.addView(day5Label); |
154 |
rowHighs.addView(day5High); |
155 |
rowLows.addView(day5Low); |
156 |
rowConditions.addView(day5Conditions); |
157 |
|
158 |
table.addView(rowTitle); |
159 |
table.addView(rowDayLabels); |
160 |
table.addView(rowHighs); |
161 |
table.addView(rowLows); |
162 |
table.addView(rowConditions); |
163 |
|
164 |
setContentView(table); |
165 |
|
166 |
} |
Vamos a echar un vistazo más de cerca al código anterior de Java. Primero, creamos un control TableLayout y configuramos los atributos encogible y estirable en true para todas las columnas usando los métodos setStretchAllColumns() y setShrinkAllColumns(). Después, sistemáticamente creamos cinco TableRow. Cada TableRow contendrá controles view (los controles TextView para el título, fechas, datos así como también controles ImageView para los gráficos de las condiciones del clima). Verá como la columna expandida está controlada con el primer TableRow. Específicas columnas de views son creadas, arregladas, para el apropiado TableRow usando el método addView(). Cada TableRow es agregado al control TableLayout, en orden, usando el método addView() del TableLayout. Finalmente, cargamos el TableLayout y lo mostramos en la pantalla usando el método setContentView().
Como puede ver, el código puede rápidamente aumentar en tamaño en la medida que más controles son añadidos a la pantalla. Para la organización y mantenimiento, definiendo y usando layouts por medio de programación lo mejor que queda para algún caso es la norma. De manera adicional, en un caso como éste, los datos normalmente vendrían de parte de alguna otra fuente que los strings que escribimos, por lo que un ciclo puede ser más apropiado para muchas aplicaciones.
Los resultados se muestran en la siguiente imagen. Como puede ver, son los mismos resultados que mostramos anteriormente, tal y como se esperaba.


Inquietudes acerca de las TableLayout
Aunque las table layouts pueden ser utilizadas para diseñar interfaz de usuarios enteras, en realidad, no son la mejor herramienta para hacer eso, como son derivadas de las LinearLayout y no de los controles layout más eficientes. Si piensa en ello, un TableLayout es más que organizar un conjunto de LinearLayouts anidados, y los layouts anidados demasiado son generalmente desestimado en lo que concierne a rendimiento. Sin embargo, para datos que ya están en un formato adecuado para una tabla, tales como datos de hojas de cálculo, los table layout pueden ser una opción razonable.
Además, los datos table layout pueden varia dependiendo de los tamaños de pantalla y resoluciones. Es, generalmente, una buena práctica de diseño para garantizarle la habilidad de desplazarse cuando muestre grandes cantidades de datos. Por ejemplo, si el ejemplo del clima que usamos anteriormente, incluye una de las condiciones "redactar", este texto podría ser una oración o veinte oraciones, así que activar el desplazamiento vertical u horizontal sería lo más prudente.
En conclusión
La aplicación de interfaz de usuario Android está definidas usando layouts, y los table layout son increíblemente prácticos para mostrar vista de datos o controles en filas y columnas. Usando la table layout donde son más adecuadas puede hacer que muchos diseños de pantalla sean más sencillos y rápidos. Sin embargo, tenga en cuenta que los TableLayout son derivados de los LinearLayout, y tienen muchas de las limitaciones de rendimiento que tienen estos.
Acerca de 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. 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.






