Diseño de Interfaz de Usuario Android: Los fundamentos de Orden de los Controles Centrales
Spanish (Español) translation by Rodney Martinez (you can also view the original English article)
No hay nada más molesto que tratar de navegar a través de una interfaz mal diseñada en una aplicación móvil. Cómo funciona sus aplicaciones en términos de navegación en pantalla puede significar la diferencia entre un usuario feliz y uno que se irrita contra usted en el Android Market. Hoy, nos concentraremos en focus —es decir: el control focus y cómo personalizarlo dentro de su interfaz de usuario.
Los métodos de entrada de los dispositivos Android se están volviéndose muy diversos: control direccional, rueda de desplazamiento, panel táctil y mucho más. Algunos dispositivos, como las tables, son navegadas principalmente por medio de tacto. Otros como Google TV, no tienen pantalla táctil de ningún modo y dependen de los dispositivos de entrada tales como esos controles direccionales (d-pad).
Los desarrolladores Android necesitan entender como navegan los usuarios con los controles en una pantalla, cómo y en que orden estos controles de pantallas ganan y pierden enfoque, y cómo personalizar el control focus para sus aplicaciones para ofrecerle a los usuarios una experiencia libre de frustración.
Entendiendo el control Focus
La plataforma Android hace lo mejor para determinar un control apropiado para un tipo de layout dado. En muchos casos, el orden por defecto de los focus tiene sentido. Sin embargo, no siempre es el caso. Cuál control debería de ser el siguiente focus en ganar está determinado a través de encontrar el focus en curso que esté más cerca del control vecino en una dirección dada (arriba/abajo/izquierda/derecha). Cuando hay múltiples controles que encajen en esa descripción, la plataforma hace un escaneo desde la izquierda hacia la derecha, de arriba hacia abajo, parecido a como podría hacerlo cuando lee un libro.
Esto tiene algunas ramificaciones. Por defecto, el control más arriba en la pantalla no tendría enfoque si el usuario navegó hacia "Arriba", ni ocurriría nada si el usuario navegará hacia "abajo" desde el fondo de la pantalla. De manera similar, nada ocurriría si el usuario tratará de navegar a la "izquierda" desde el control más a la izquierda o hacia la "Derecha" desde el control más a la derecha. No hay ningún "wrapping", por defecto.
Ahora, veamos un ejemplo de como podría modificar el funcionamiento de los focus por defecto en una pantalla y hacerlo funcionar para usted y para sus usuarios. Por ejemplo, digamos que quiere empujar el orden del focus para enrollar alrededor un conjunto de controles que constituyen una cara de reloj.
Paso 0: Empezando
Ofrecemos todo el recurso del código para la aplicación de muestra que discutiremos en este tutorial. Usted puede descargar la muestra del recurso del código que proporcionamos para revisarlo aquí.
Paso 1: Define un layout con controles
Primero, haga y edite el archivo layour resource usado por su clase Activity, tal como /res/layout/main.xml. Por ejemplo, el siguiente layout define un tipo de "cara de reloj" de controles de Buttons usando un RelativeLayout.
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<RelativeLayout
|
4 |
xmlns:android="http://schemas.android.com/apk/res/android" |
5 |
android:layout_width="fill_parent" |
6 |
android:layout_height="fill_parent"> |
7 |
<Button
|
8 |
style="@style/clockFaceNum" |
9 |
android:text="12" |
10 |
android:id="@+id/button12" |
11 |
android:layout_alignParentTop="true" |
12 |
android:layout_centerHorizontal="true"> |
13 |
</Button>
|
14 |
<Button
|
15 |
style="@style/clockFaceNum" |
16 |
android:text="11" |
17 |
android:id="@+id/button11" |
18 |
android:layout_below="@+id/button12" |
19 |
android:layout_toLeftOf="@+id/button12"> |
20 |
</Button>
|
21 |
<Button
|
22 |
style="@style/clockFaceNum" |
23 |
android:text="1" |
24 |
android:id="@+id/button1" |
25 |
android:layout_below="@+id/button12" |
26 |
android:layout_toRightOf="@+id/button12"> |
27 |
</Button>
|
28 |
<Button
|
29 |
style="@style/clockFaceNum" |
30 |
android:text="10" |
31 |
android:id="@+id/button10" |
32 |
android:layout_below="@+id/button11" |
33 |
android:layout_toLeftOf="@+id/button11"> |
34 |
</Button>
|
35 |
<Button
|
36 |
style="@style/clockFaceNum" |
37 |
android:text="2" |
38 |
android:id="@+id/button2" |
39 |
android:layout_below="@+id/button1" |
40 |
android:layout_toRightOf="@+id/button1"> |
41 |
</Button>
|
42 |
<Button
|
43 |
style="@style/clockFaceNum" |
44 |
android:text="9" |
45 |
android:id="@+id/button9" |
46 |
android:layout_below="@+id/button10" |
47 |
android:layout_toLeftOf="@+id/button10"> |
48 |
</Button>
|
49 |
|
50 |
<Button
|
51 |
style="@style/clockFaceNum" |
52 |
android:text="3" |
53 |
android:id="@+id/button3" |
54 |
android:layout_below="@+id/button2" |
55 |
android:layout_toRightOf="@+id/button2"> |
56 |
</Button>
|
57 |
<Button
|
58 |
style="@style/clockFaceNum" |
59 |
android:text="8" |
60 |
android:id="@+id/button8" |
61 |
android:layout_below="@+id/button9" |
62 |
android:layout_toRightOf="@+id/button9"> |
63 |
</Button>
|
64 |
<Button
|
65 |
style="@style/clockFaceNum" |
66 |
android:text="4" |
67 |
android:id="@+id/button4" |
68 |
android:layout_below="@+id/button3" |
69 |
android:layout_toLeftOf="@+id/button3"> |
70 |
</Button>
|
71 |
<Button
|
72 |
style="@style/clockFaceNum" |
73 |
android:text="7" |
74 |
android:id="@+id/button7" |
75 |
android:layout_below="@+id/button8" |
76 |
android:layout_toRightOf="@+id/button8"> |
77 |
</Button>
|
78 |
<Button
|
79 |
style="@style/clockFaceNum" |
80 |
android:text="5" |
81 |
android:id="@+id/button5" |
82 |
android:layout_below="@+id/button4" |
83 |
android:layout_toLeftOf="@+id/button4"> |
84 |
</Button>
|
85 |
<Button
|
86 |
style="@style/clockFaceNum" |
87 |
android:text="6" |
88 |
android:id="@+id/button6" |
89 |
android:layout_below="@+id/button5" |
90 |
android:layout_centerHorizontal="true"> |
91 |
</Button>
|
92 |
</RelativeLayout>
|
El estilo llamado clockFaceNum está definido en el archivo /res/values/styles.xml de la siguiente manera:
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<resources>
|
4 |
<style
|
5 |
name="clockFaceNum"> |
6 |
<item
|
7 |
name="android:layout_width">38dp</item> |
8 |
<item
|
9 |
name="android:layout_height">38dp</item> |
10 |
<item
|
11 |
name="android:onClick">numClicked</item> |
12 |
<item
|
13 |
name="android:textSize">9sp</item> |
14 |
</style>
|
15 |
</resources>
|
La pantalla de resultado luce así:


Paso 2: Revise el Orden por Defecto del Focus
Vamos a revisar el orden por defecto del focus para la cara de reloj de los controles Button en este RelativeLayout. Si el usuario está concentrado en 12 botones y presiona "abajo" en un control direccional, entonces el siguiente control a tomar el focus será el Button 11, seguido por el Button 10, y así sucesivamente.
La ruta por defecto "Abajo" se muestra aquí:


Paso 3: Proporcione un Control Personalizado para el Orden focus
Digamos que queremos obligar al usuario para que solamente sea capaz de cruzar los controles de la cara de reloj en el sentido de las manecillas del reloj o en sentido contrario a las manecillas del reloj, es decir; lo opuesto al orden por defecto del focus, como se muestra a continuación:


Podemos definir este comportamiento por medio de la especificación, para cada Button, cual control sería el siguiente focus. Hay cuatro atributos XML que puede configurar en cualquier control View para definir el orden del focus. Estos atributos son:
- android:nextFocusUp-este atributo define el control que debería de ganar enfoque si el usuario navega hacia arriba.
- android:nextFocusDown-este atributo define el control que debería ganar enfoque si el usuario navegará hacia abajo.
- android:nextFocusLeft-este atributo define el control que debería ganar enfoque si el usuario navegará hacia la izquierda.
- android:nextFocusRight-este atributo define el control que debería ganar enfoque si el usuario navegará hacia la derecha.
Digamos que queremos que todos los controles de navegación "Abajo" y "Derecha", permitan al usuario cruzar los controles de Buttons del layout clock face en el sentido de las manecillas del reloj, y que todos los controles "Arriba" y "Izquierda" permitan a los usuarios cruzar los controles en el sentido contrario a la las manecillas del reloj. Luego, tendríamos que definir estos cuatro atributos para cada control. Por ejemplo, si usted se mueve hacia "Abajo" o "Derecha" desde el Button 12, entonces alcanzaría el Button 1. De manera similar, si se mueve hacia "Arriba" o a la "Izquierda" desde el Button 12, entonces alcanzaría el Button 11.
Una definición completa de este nuevo layout clock face luce así:
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<RelativeLayout
|
4 |
xmlns:android="http://schemas.android.com/apk/res/android" |
5 |
android:layout_width="fill_parent" |
6 |
android:layout_height="fill_parent"> |
7 |
<Button
|
8 |
style="@style/clockFaceNum" |
9 |
android:text="12" |
10 |
android:id="@+id/button12" |
11 |
android:layout_alignParentTop="true" |
12 |
android:layout_centerHorizontal="true" |
13 |
android:nextFocusUp="@+id/button11" |
14 |
android:nextFocusLeft="@+id/button11" |
15 |
android:nextFocusRight="@+id/button1" |
16 |
android:nextFocusDown="@+id/button1"> |
17 |
</Button>
|
18 |
<Button
|
19 |
style="@style/clockFaceNum" |
20 |
android:text="11" |
21 |
android:id="@+id/button11" |
22 |
android:layout_below="@+id/button12" |
23 |
android:layout_toLeftOf="@+id/button12" |
24 |
android:nextFocusUp="@+id/button10" |
25 |
android:nextFocusLeft="@+id/button10" |
26 |
android:nextFocusRight="@+id/button12" |
27 |
android:nextFocusDown="@+id/button12"> |
28 |
</Button>
|
29 |
<Button
|
30 |
style="@style/clockFaceNum" |
31 |
android:text="1" |
32 |
android:id="@+id/button1" |
33 |
android:layout_below="@+id/button12" |
34 |
android:layout_toRightOf="@+id/button12" |
35 |
android:nextFocusUp="@+id/button12" |
36 |
android:nextFocusLeft="@+id/button12" |
37 |
android:nextFocusRight="@+id/button2" |
38 |
android:nextFocusDown="@+id/button2"> |
39 |
</Button>
|
40 |
<Button
|
41 |
style="@style/clockFaceNum" |
42 |
android:text="10" |
43 |
android:id="@+id/button10" |
44 |
android:layout_below="@+id/button11" |
45 |
android:layout_toLeftOf="@+id/button11" |
46 |
android:nextFocusUp="@+id/button9" |
47 |
android:nextFocusLeft="@+id/button9" |
48 |
android:nextFocusRight="@+id/button11" |
49 |
android:nextFocusDown="@+id/button11"> |
50 |
</Button>
|
51 |
<Button
|
52 |
style="@style/clockFaceNum" |
53 |
android:text="2" |
54 |
android:id="@+id/button2" |
55 |
android:layout_below="@+id/button1" |
56 |
android:layout_toRightOf="@+id/button1" |
57 |
android:nextFocusUp="@+id/button1" |
58 |
android:nextFocusLeft="@+id/button1" |
59 |
android:nextFocusRight="@+id/button3" |
60 |
android:nextFocusDown="@+id/button3"> |
61 |
</Button>
|
62 |
<Button
|
63 |
style="@style/clockFaceNum" |
64 |
android:text="9" |
65 |
android:id="@+id/button9" |
66 |
android:layout_below="@+id/button10" |
67 |
android:layout_toLeftOf="@+id/button10" |
68 |
android:nextFocusUp="@+id/button8" |
69 |
android:nextFocusLeft="@+id/button8" |
70 |
android:nextFocusRight="@+id/button10" |
71 |
android:nextFocusDown="@+id/button10"> |
72 |
</Button>
|
73 |
|
74 |
<Button
|
75 |
style="@style/clockFaceNum" |
76 |
android:text="3" |
77 |
android:id="@+id/button3" |
78 |
android:layout_below="@+id/button2" |
79 |
android:layout_toRightOf="@+id/button2" |
80 |
android:nextFocusUp="@+id/button2" |
81 |
android:nextFocusLeft="@+id/button2" |
82 |
android:nextFocusRight="@+id/button4" |
83 |
android:nextFocusDown="@+id/button4"> |
84 |
</Button>
|
85 |
<Button
|
86 |
style="@style/clockFaceNum" |
87 |
android:text="8" |
88 |
android:id="@+id/button8" |
89 |
android:layout_below="@+id/button9" |
90 |
android:layout_toRightOf="@+id/button9" |
91 |
android:nextFocusUp="@+id/button7" |
92 |
android:nextFocusLeft="@+id/button7" |
93 |
android:nextFocusRight="@+id/button9" |
94 |
android:nextFocusDown="@+id/button9"> |
95 |
</Button>
|
96 |
<Button
|
97 |
style="@style/clockFaceNum" |
98 |
android:text="4" |
99 |
android:id="@+id/button4" |
100 |
android:layout_below="@+id/button3" |
101 |
android:layout_toLeftOf="@+id/button3" |
102 |
android:nextFocusUp="@+id/button3" |
103 |
android:nextFocusLeft="@+id/button3" |
104 |
android:nextFocusRight="@+id/button5" |
105 |
android:nextFocusDown="@+id/button5"> |
106 |
</Button>
|
107 |
<Button
|
108 |
style="@style/clockFaceNum" |
109 |
android:text="7" |
110 |
android:id="@+id/button7" |
111 |
android:layout_below="@+id/button8" |
112 |
android:layout_toRightOf="@+id/button8" |
113 |
android:nextFocusUp="@+id/button6" |
114 |
android:nextFocusLeft="@+id/button6" |
115 |
android:nextFocusRight="@+id/button8" |
116 |
android:nextFocusDown="@+id/button8"> |
117 |
</Button>
|
118 |
<Button
|
119 |
style="@style/clockFaceNum" |
120 |
android:text="5" |
121 |
android:id="@+id/button5" |
122 |
android:layout_below="@+id/button4" |
123 |
android:layout_toLeftOf="@+id/button4" |
124 |
android:nextFocusUp="@+id/button4" |
125 |
android:nextFocusLeft="@+id/button4" |
126 |
android:nextFocusRight="@+id/button6" |
127 |
android:nextFocusDown="@+id/button6"> |
128 |
</Button>
|
129 |
<Button
|
130 |
style="@style/clockFaceNum" |
131 |
android:text="6" |
132 |
android:id="@+id/button6" |
133 |
android:layout_below="@+id/button5" |
134 |
android:layout_centerHorizontal="true" |
135 |
android:nextFocusUp="@+id/button5" |
136 |
android:nextFocusLeft="@+id/button5" |
137 |
android:nextFocusRight="@+id/button7" |
138 |
android:nextFocusDown="@+id/button7"> |
139 |
</Button>
|
140 |
</RelativeLayout>
|
Por lo tanto, nuestra nueva trayectoria "Abajo", iniciará en el Button 12, así como luce ahora:


Paso 4: Configuración Inicial del Control Focus
Finalmente, aquí está un truco para configurar el control por defecto para ganar focus en una pantalla de color verde desde la parte interior de su archivo layout. Usted puede hacer esto para un control View en cada archivo.
Use la etiqueta dentro del control View para ajustar el focus inicial de la pantalla. Por ejemplo, podríamos querer que actualice el Button 12 para obtener el focus inicial, como este:
1 |
|
2 |
<Button |
3 |
style="@style/clockFaceNum" |
4 |
android:text="12" |
5 |
android:id="@+id/button12" |
6 |
android:layout_alignParentTop="true" |
7 |
android:layout_centerHorizontal="true" |
8 |
android:nextFocusUp="@+id/button11" |
9 |
android:nextFocusLeft="@+id/button11" |
10 |
android:nextFocusRight="@+id/button1" |
11 |
android:nextFocusDown="@+id/button1"> |
12 |
<requestFocus /> |
13 |
</Button> |
Usted puede, por supuesto, usar los métodos por medio de programación para ajustar el control focus, usando el método de la clase View llamado requestFocus().
En conclusión
Los programadores Android necesitan recordar que diferentes usuarios navegarán en una interfaz de usuario de una aplicación usando diferentes métodos de entrada. Algunos métodos hacen fácil saltar entre los controles de pantalla, mientras que otros puede hacer que la navegación sea muy compleja. Los desarrolladores pueden proporcionar focus personalizados ordenados que pueden mejorar mucho la experiencia de los usuarios con la aplicación. Por favor, no se olvide del teclado de los usuarios. ☺
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, 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.






