1. Introducción
Los usuarios pueden interactuar con tu app con un teclado físico, por lo general, en dispositivos con pantalla grande, como tablets y dispositivos ChromeOS, pero también en dispositivos de realidad extendida. Es importante que los usuarios puedan navegar por tu app con la misma eficacia con un teclado físico que con una pantalla táctil. Además, cuando diseñes tu app para pantallas de TV y automóviles, que pueden no tener entrada táctil y, en su lugar, depender de pads direccionales o codificadores rotativos, debes aplicar principios de navegación del teclado similares.
Compose te permite controlar las entradas de teclados físicos, pads direccionales y codificadores rotativos de forma unificada. Un principio clave de una buena experiencia del usuario para estos métodos de entrada es que los usuarios puedan mover el enfoque del teclado de forma intuitiva y coherente al componente interactivo con el que quieren interactuar.
En este codelab, aprenderás lo siguiente:
- Implementar patrones comunes de administración de enfoque del teclado para una navegación intuitiva y coherente
- Probar si el movimiento del enfoque del teclado se comporta como se espera
Requisitos previos
- Experiencia en el desarrollo de apps con Compose
- Conocimientos básicos de Kotlin, incluidas lambdas y corrutinas
Qué crearás
Implementarás los siguientes patrones típicos de administración de enfoque del teclado:
- Movimiento del enfoque del teclado: De principio a fin, de arriba abajo en el patrón en forma de Z
- Enfoque inicial lógico: Establece el enfoque en el elemento de la IU con el que es probable que el usuario interactúe.
- Restauración del enfoque: Mueve el enfoque al elemento de la IU con el que el usuario interactuó anteriormente.
Qué aprenderás
- Aspectos básicos de la administración de enfoque en Compose
- Cómo establecer un elemento de la IU como objetivo de enfoque
- Cómo solicitar el enfoque para mover un elemento de la IU
- Cómo mover el enfoque del teclado a un elemento de la IU específico en un grupo de elementos de la IU
Requisitos
- Android Studio Ladybug o una versión posterior
- Cualquiera de los siguientes dispositivos para ejecutar la app de ejemplo:
- Un dispositivo con pantalla grande y un teclado físico
- Un dispositivo virtual de Android para dispositivos con pantalla grande, como el emulador con cambio de tamaño
2. Configuración
- Clona el repositorio de GitHub de codelabs de pantallas grandes:
git clone https://github.com/android/large-screen-codelabs
Otra opción es descargar y desarchivar el archivo ZIP de codelabs de pantallas grandes:
- Navega a la carpeta
focus-management-in-compose
. - En Android Studio, abre el proyecto. La carpeta
focus-management-in-compose
contiene un proyecto. - Si no tienes una tablet Android, un dispositivo plegable o un dispositivo ChromeOS con un teclado físico, abre Device Manager en Android Studio y, luego, crea el dispositivo de tamaño variable en la categoría Phone.
Figura 1: Cómo configurar el emulador de tamaño variable en Android Studio
3. Explora el código de partida
El proyecto tiene dos módulos:
- start: Contiene el código de partida del proyecto. Realiza cambios en esta rama para completar el codelab.
- solution: Contiene el código completo para este codelab.
La app de ejemplo consta de tres pestañas:
- Objetivo de enfoque
- Orden de recorrido del enfoque
- Grupo de enfoque
La pestaña de objetivo de enfoque se muestra cuando se inicia la app.
Figura 2: La pestaña Objetivo de enfoque se muestra cuando se inicia la app.
El paquete ui
contiene el siguiente código de IU con el que interactúas:
App.kt
: Implementa pestañas.tab.FocusTargetTab.kt
: Contiene el código de la pestaña de objetivo de enfoque.tab.FocusTraversalOrderTab.kt
: Contiene el código de la pestaña de orden de recorrido de enfoque.tab.FocusGroup.kt
: Contiene el código de la pestaña del grupo de enfoque.FocusGroupTabTest.kt
: Es una prueba de instrumentación paratab.FocusTargetTab.kt
(el archivo se encuentra en la carpetaandroidTest
).
4. Objetivo de enfoque
Un objetivo de enfoque es un elemento de la IU al que se puede mover el enfoque del teclado. Los usuarios pueden mover el enfoque del teclado con la tecla Tab
o las teclas direccionales (flechas):
- Tecla
Tab
: El enfoque se mueve al siguiente objetivo de enfoque o al anterior de manera unidimensional. - Teclas de dirección: El enfoque puede moverse en dos dimensiones: arriba, abajo, izquierda y derecha.
Las pestañas son objetivos de enfoque. En la app de ejemplo, el fondo de las pestañas se actualiza visualmente cuando la pestaña adquiere el enfoque.
Figura 3: El fondo del componente cambia cuando el enfoque se mueve a un objetivo de enfoque.
Los elementos interactivos de la IU son objetivos de enfoque de forma predeterminada
Un componente interactivo es un objetivo de enfoque de forma predeterminada. En otras palabras, el elemento de la IU es un objetivo de enfoque si los usuarios pueden presionarlo.
La app de ejemplo tiene tres tarjetas en la pestaña Objetivo de enfoque. La primera tarjeta y la tercera tarjeta son objetivos de enfoque, pero la segunda tarjeta no lo es. El fondo de la tercera tarjeta se actualiza cuando el usuario mueve el enfoque de la primera tarjeta con la tecla Tab
.
Figura 4: Los objetivos de enfoque de la aplicación excluyen la segunda tarjeta.
Modifica la segunda tarjeta para que sea un objetivo de enfoque
Para hacer que la segunda tarjeta sea un objetivo de enfoque, cámbiala a un elemento interactivo de la IU. La forma más fácil es usar el modificador clickable
de la siguiente manera:
- Abre
FocusTargetTab.kt
en el paquetetabs
- Modifica el elemento
SecondCard
componible con el modificadorclickable
de la siguiente manera:
@Composable
fun FocusTargetTab(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier
) {
FirstCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
SecondCard(
modifier = Modifier
.width(240.dp)
.clickable(onClick = onClick)
)
ThirdCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
}
}
Ejecución
Ahora, el usuario puede mover el enfoque a la segunda tarjeta, además de la primera tarjeta y la tercera tarjeta. Puedes probarlo en la pestaña Objetivo de enfoque. Confirma que puedes mover el enfoque de la primera tarjeta a la segunda tarjeta con la tecla Tab
.
Figura 5: Se mueve el enfoque de la primera tarjeta a la segunda tarjeta con la tecla Tab
.
5. Navegación de enfoque en un patrón en forma de Z
Los usuarios esperan que el enfoque del teclado se mueva de izquierda a derecha y de arriba abajo en la configuración de idioma de izquierda a derecha. Este orden de recorrido del enfoque se denomina patrón en forma de Z.
Sin embargo, Compose ignora el diseño cuando determina el siguiente objetivo de enfoque de la tecla Tab
y, en su lugar, usa el recorrido de enfoque unidimensional según el orden de las llamadas a funciones componibles.
Recorrido de enfoque unidimensional
El orden de recorrido de enfoque unidimensional proviene del orden de las llamadas a funciones de componibilidad en lugar del diseño de la app.
En la app de ejemplo, el enfoque se mueve en el siguiente orden en la pestaña orden de recorrido de enfoque:
- Primera tarjeta
- Cuarta tarjeta
- Tercera tarjeta
- Segunda tarjeta
Figura 6: El recorrido del enfoque sigue el orden de las funciones de componibilidad.
La función FocusTraversalOrderTab
implementa la pestaña de recorrido de enfoque de la app de ejemplo. La función llama a funciones componibles para las tarjetas: FirstCard
, FourthCard
, ThirdCard
y SecondCard
, en ese orden.
@Composable
fun FocusTraversalOrderTab(
modifier: Modifier = Modifier
) {
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
FirstCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
FourthCard(
onClick = onClick,
modifier = Modifier
.width(240.dp)
.offset(x = 256.dp)
)
ThirdCard(
onClick = onClick,
modifier = Modifier
.width(240.dp)
.offset(y = (-151).dp)
)
}
SecondCard(
modifier = Modifier.width(240.dp)
)
}
}
Movimiento de enfoque en un patrón en forma de Z
Puedes integrar el movimiento de enfoque en forma de Z en la pestaña orden de recorrido de enfoque de la app de ejemplo siguiendo estos pasos:
- Abre
tabs.FocusTraversalOrderTab.kt
- Quita el modificador de offset de los elementos
ThirdCard
yFourthCard
componibles. - Cambia el diseño de la pestaña a una columna con dos filas de la fila actual con dos columnas.
- Mueve los elementos componibles
FirstCard
ySecondCard
a la primera fila. - Mueve los elementos componibles
ThirdCard
yFourthCard
a la segunda fila.
El código modificado es el siguiente:
@Composable
fun FocusTraversalOrderTab(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier
) {
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
FirstCard(
onClick = onClick,
modifier = Modifier.width(240.dp),
)
SecondCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
ThirdCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
FourthCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
}
}
}
Ejecución
Ahora, el usuario puede mover el enfoque de derecha a izquierda y de arriba abajo en el patrón en forma de Z. Puedes probarlo en la pestaña orden de recorrido de enfoque y confirmar que el enfoque se mueve en el siguiente orden con la tecla Tab
:
- Primera tarjeta
- Segunda tarjeta
- Tercera tarjeta
- Cuarta tarjeta
Figura 7: Navegación de enfoque en un patrón en forma de Z.
6: focusGroup
El enfoque se mueve de la primera tarjeta a la tercera tarjeta con la tecla de dirección right
en la pestaña Grupo de enfoque. Es probable que el movimiento sea un poco confuso para los usuarios, ya que las dos tarjetas no están una al lado de la otra.
Figura 8: Se produce un movimiento de enfoque inesperado de la primera tarjeta a la tercera tarjeta.
La navegación de enfoque de dos dimensiones hace referencia a la información de diseño.
Si presionas una tecla de dirección, se activa el recorrido de enfoque en dos dimensiones. Este es un recorrido de enfoque común en las TVs, ya que los usuarios interactúan con tu app con un pad direccional. Si presionas las teclas de flecha del teclado, también se activa el recorrido de enfoque en dos dimensiones, ya que imitan la navegación con un pad direccional.
En el recorrido de enfoque en dos dimensiones, el sistema se refiere a la información geométrica de los elementos de la IU y determina el objetivo de enfoque para mover el enfoque. Por ejemplo, el enfoque se mueve a la primera tarjeta desde la pestaña de destino de enfoque con la tecla de dirección down
, y presionar la tecla de dirección hacia arriba mueve el enfoque a la pestaña de objetivo de enfoque.
Figura 9: Desplazamiento del enfoque con teclas de dirección hacia abajo y hacia arriba
El recorrido del enfoque en dos dimensiones no se une, a diferencia del recorrido de enfoque en una dimensión con la tecla Tab
. Por ejemplo, el usuario no puede mover el enfoque con la tecla de flecha hacia abajo cuando se enfoca la segunda tarjeta.
Figura 10: La tecla de flecha hacia abajo no puede mover el enfoque cuando se enfoca la segunda tarjeta.
Los objetivos de enfoque están en el mismo nivel
En el siguiente código, se implementa la pantalla mencionada anteriormente. Hay cuatro objetivos de enfoque: FirstCard
, SecondCard
, ThirdCard
y FourthCard
. Estos cuatro objetivos de enfoque están en el mismo nivel, y ThirdCard
es el primer elemento a la derecha de FirstCard
en el diseño. Es por eso que el enfoque se mueve a la tercera tarjeta desde la primera tarjeta con la tecla de dirección right
.
@Composable
fun FocusGroupTab(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier,
) {
FirstCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
SecondCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
ThirdCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
FourthCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
}
}
}
Agrupa los destinos de enfoque con el modificador focusGroup
Puedes cambiar el movimiento de enfoque confuso con los siguientes pasos:
- Abre
tabs.FocusGroup.kt
- Modifica la función de componibilidad
Column
en la función de componibilidadFocusGroupTab
con el modificadorfocusGroup
.
El código actualizado es el siguiente:
@Composable
fun FocusGroupTab(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier,
) {
FirstCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.focusGroup(),
) {
SecondCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
ThirdCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
FourthCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
}
}
}
El modificador focusGroup
crea un grupo de enfoque que consta de los objetivos de enfoque dentro del componente modificado. Los objetivos de enfoque dentro del grupo de enfoque y los que están fuera de él se encuentran en diferentes niveles, y no hay un objetivo de enfoque ubicado en el lado derecho del elemento componible FirstCard
. Como resultado, el enfoque no se mueve a ninguna tarjeta de la primera tarjeta con la tecla de dirección right
.
Ejecución
Ahora, el enfoque no se mueve a la tercera tarjeta desde la primera tarjeta con la tecla de dirección right
en la pestaña Grupo de enfoque de la app de ejemplo.
7. Solicita enfoque
Los usuarios no pueden usar teclados ni pads direccionales para seleccionar elementos arbitrarios de la IU con los que interactuar. Los usuarios deben mover el enfoque del teclado a un componente interactivo antes de interactuar con el elemento.
Por ejemplo, los usuarios deben mover el enfoque de la pestaña Objetivo de enfoque a la primera tarjeta antes de interactuar con ella. Puedes reducir la cantidad de acciones para iniciar la tarea principal del usuario si configuras lógicamente el enfoque inicial.
Figura 11: Tres presiones de la tecla Tab
desplazan el enfoque a la primera tarjeta.
Cómo solicitar enfoque con FocusRequester
Puedes solicitar el enfoque para mover un elemento de la IU con FocusRequester
. Se debe asociar un objeto FocusRequester
con un elemento de la IU antes de llamar al método requestFocus()
.
Establece el enfoque inicial en la primera tarjeta
Puedes establecer el enfoque inicial en la primera tarjeta con los siguientes pasos:
- Abre
tabs.FocusTarget.kt
- Declara el valor
firstCard
en la función de componibilidadFocusTargetTab
y, luego, inicialízalo con un objetoFocusRequester
que se devuelve de la funciónremember
. - Modifica la función de componibilidad
FirstCard
con el modificadorfocusRequester
. - Especifica el valor
firstCard
como el argumento del modificadorfocusRequester
. - Llama a la función de componibilidad
LaunchedEffect
con el valorUnit
y llama al método requestFocus() sobre el valorfirstCard
en la expresión lambda pasada a la función de componibilidadLaunchedEffect
.
Se crea un objeto FocusRequester
y se asocia con un elemento de la IU en el segundo y tercer paso. En el quinto paso, se solicita el enfoque para que se mueva al elemento de la IU asociado cuando se compone el elemento componible FocusdTargetTab
por primera vez.
El código actualizado se verá de la siguiente manera:
@Composable
fun FocusTargetTab(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val firstCard = remember { FocusRequester() }
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier
) {
FirstCard(
onClick = onClick,
modifier = Modifier
.width(240.dp)
.focusRequester(focusRequester = firstCard)
)
SecondCard(
modifier = Modifier
.width(240.dp)
.clickable(onClick = onClick)
)
ThirdCard(
onClick = onClick,
modifier = Modifier.width(240.dp)
)
}
LaunchedEffect(Unit) {
firstCard.requestFocus()
}
}
Ejecución
Ahora, el enfoque del teclado se mueve a la primera tarjeta en la pestaña Objeto de enfoque cuando se selecciona la pestaña. Para probarlo, cambia de pestaña. Además, se selecciona la primera tarjeta cuando se inicia la app.
Figura 12: El enfoque se mueve a la primera tarjeta cuando se selecciona la pestaña Objetivo de enfoque.
8. Mueve el enfoque a la pestaña seleccionada
Puedes especificar el objetivo de enfoque cuando el enfoque del teclado ingresa a un grupo de enfoque. Por ejemplo, puedes mover el enfoque a la pestaña seleccionada cuando el usuario lo mueve a la fila de pestañas.
Puedes implementar este comportamiento con los siguientes pasos:
- Abre
App.kt
. - Declara el valor
focusRequesters
en la función de componibilidadApp
. - Inicializa el valor
focusRequesters
con el valor que se muestra de la funciónremember
, que muestra una lista de objetosFocusRequester
. La longitud de la lista que se muestra debe ser igual a la deScreens.entries
. - Asocia cada objeto
FocusRequester
del valorfocusRequester
con el elementoTab
componible modificando el elemento Tab componible con el modificadorfocusRequester
. - Modifica el elemento componible PrimaryTabRow con el modificador
focusProperties
y el modificadorfocusGroup
. - Pasa una lambda al modificador
focusProperties
y asocia la propiedadenter
con otra lambda. - Muestra FocusRequester, que está indexado con el valor
selectedTabIndex
en el valorfocusRequesters
, desde la lambda asociada con la propiedadenter
.
El código modificado se ve de la siguiente manera:
@Composable
fun App(
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
var selectedScreen by rememberSaveable { mutableStateOf(Screen.FocusTarget) }
val selectedTabIndex = Screen.entries.indexOf(selectedScreen)
val focusRequesters = remember {
List(Screen.entries.size) { FocusRequester() }
}
Column(modifier = modifier) {
PrimaryTabRow(
selectedTabIndex = selectedTabIndex,
modifier = Modifier
.focusProperties {
enter = {
focusRequesters[selectedTabIndex]
}
}
.focusGroup()
) {
Screen.entries.forEachIndexed { index, screen ->
Tab(
selected = screen == selectedScreen,
onClick = { selectedScreen = screen },
text = { Text(stringResource(screen.title)) },
modifier = Modifier.focusRequester(focusRequester = focusRequesters[index])
)
}
}
when (selectedScreen) {
Screen.FocusTarget -> {
FocusTargetTab(
onClick = context::onCardClicked,
modifier = Modifier.padding(32.dp),
)
}
Screen.FocusTraversalOrder -> {
FocusTraversalOrderTab(
onClick = context::onCardClicked,
modifier = Modifier.padding(32.dp)
)
}
Screen.FocusRestoration -> {
FocusGroupTab(
onClick = context::onCardClicked,
modifier = Modifier.padding(32.dp)
)
}
}
}
}
Puedes controlar el movimiento del enfoque con el modificador focusProperties
. En la lambda que se pasa al modificador, modifica FocusProperties, al que se hace referencia cuando el sistema elige el objetivo de enfoque cuando los usuarios presionan la tecla Tab
o las teclas de dirección cuando el elemento de la IU modificado está enfocado.
Cuando configuras la propiedad enter
, el sistema evalúa la lambda establecida en la propiedad y se mueve al elemento de la IU que está asociado con el objeto FocusRequester
que muestra la lambda evaluada.
Ejecución
Ahora, el enfoque del teclado se mueve a la pestaña seleccionada cuando el usuario mueve el enfoque a la fila de pestañas. Puedes probarlo con los siguientes pasos:
- Ejecuta la app
- Selecciona la pestaña Grupo de enfoque.
- Mueve el enfoque a la primera tarjeta con la tecla de dirección
down
. - Mueve el enfoque con la tecla de dirección
up
.
Figura 13: El enfoque se mueve a la pestaña seleccionada.
9. Restablecimiento del enfoque
Los usuarios esperan poder reanudar fácilmente una tarea cuando se interrumpe. El restablecimiento del enfoque admite la recuperación de una interrupción. El restablecimiento del enfoque mueve el enfoque del teclado al elemento de la IU que se seleccionó anteriormente.
Un caso de uso típico del restablecimiento del enfoque es la pantalla principal de las apps de transmisión de video. La pantalla tiene varias listas de contenido de video, como películas de una categoría o episodios de un programa de TV. Los usuarios exploran las listas y encuentran contenido interesante. A veces, los usuarios vuelven a la lista que examinaron anteriormente y continúan navegando por ella. Con el restablecimiento del enfoque, los usuarios pueden seguir navegando sin mover el enfoque del teclado al último elemento que vieron en la lista.
El modificador focusRestorer restablece el enfoque en un grupo focal.
Usa el modificador focusRestorer
para guardar y restablecer el enfoque en un grupo de enfoque. Cuando el enfoque sale del grupo de enfoque, almacena una referencia al elemento que estaba enfocado anteriormente. Luego, cuando el enfoque vuelve a ingresar al grupo de enfoque, se restablece en el elemento enfocado anteriormente.
Integra el restablecimiento del enfoque con la pestaña del grupo de enfoque
La pestaña Grupo de enfoque de la app de ejemplo tiene una fila que contiene la segunda tarjeta, la tercera tarjeta y la cuarta tarjeta.
Figura 14: Grupo de enfoque que contiene la segunda tarjeta, la tercera tarjeta y la cuarta tarjeta.
Puedes integrar el restablecimiento del enfoque en la fila con los siguientes pasos:
- Abre
tab.FocusGroupTab.kt
- Modifica el elemento
Row
componible en el elementoFocusGroupTab
componible con el modificadorfocusRestorer
. Se debe llamar al modificador antes del modificadorfocusGroup
.
El código modificado se ve de la siguiente manera:
@Composable
fun FocusGroupTab(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier,
) {
FirstCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier
.focusRestorer()
.focusGroup(),
) {
SecondCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
ThirdCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
FourthCard(
onClick = onClick,
modifier = Modifier.width(208.dp)
)
}
}
}
Ejecución
Ahora, la fila de la pestaña Grupo de enfoque restablece el enfoque, y puedes probarlo con los siguientes pasos:
- Selecciona la pestaña Grupo de enfoque.
- Mueve el enfoque a la primera tarjeta
- Mueve el enfoque a la cuarta tarjeta con la tecla
Tab
- Mueve el enfoque a la primera tarjeta con la tecla de dirección
up
- Pulsa la tecla
Tab
El enfoque del teclado se mueve a la cuarta tarjeta, ya que el modificador focusRestorer
guarda la referencia de la tarjeta y restablece el enfoque cuando el enfoque del teclado ingresa al grupo de enfoque establecido en la fila.
Figura 15: El enfoque vuelve a la cuarta tarjeta después de presionar la tecla de dirección hacia arriba seguida de la tecla Tab
.
10. Crea una prueba
Puedes probar la administración de enfoque del teclado implementada con pruebas. Compose proporciona una API para probar si un elemento de la IU está enfocado y presionar teclas en los componentes de la IU. Consulta el codelab Pruebas en Jetpack Compose para obtener más información.
Prueba la pestaña Objetivo de enfoque
En la sección anterior, modificaste la función de componibilidad FocusTargetTab
para establecer la segunda tarjeta como objetivo de enfoque. Crea una prueba de la implementación que realizaste de forma manual en la sección anterior. La prueba se puede crear con los siguientes pasos:
- Abre
FocusTargetTabTest.kt
. Modificarás la funcióntestSecondCardIsFocusTarget
en los siguientes pasos. - Para solicitar que el enfoque se mueva a la primera tarjeta, llama al método
requestFocus
en el objetoSemanticsNodeInteraction
de la primera tarjeta. - Asegúrate de que la primera tarjeta esté enfocada con el método
assertIsFocused()
. - Para presionar la tecla
Tab
, llama al métodopressKey
con el valorKey.Tab
dentro de la lambda pasada al métodoperformKeyInput
. - Para probar si el enfoque del teclado se mueve a la segunda tarjeta, llama al método
assertIsFocused()
sobre el objetoSemanticsNodeInteraction
de la segunda tarjeta.
El código actualizado se verá de la siguiente manera:
@OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
@Test
fun testSecondCardIsFocusTarget() {
composeTestRule.setContent {
LocalInputModeManager
.current
.requestInputMode(InputMode.Keyboard)
FocusTargetTab(onClick = {})
}
val context = InstrumentationRegistry.getInstrumentation().targetContext
// Ensure the 1st card is focused
composeTestRule
.onNodeWithText(context.getString(R.string.first_card))
.requestFocus()
.performKeyInput { pressKey(Key.Tab) }
// Test if focus moves to the 2nd card from the 1st card with Tab key
composeTestRule
.onNodeWithText(context.getString(R.string.second_card))
.assertIsFocused()
}
Ejecución
Para ejecutar la prueba, haz clic en el ícono triangular que se muestra a la izquierda de la declaración de la clase FocusTargetTest
. Consulta la sección Cómo ejecutar pruebas en Cómo realizar pruebas en Android Studio para obtener más información.
11. Felicitaciones
¡Bien hecho! Aprendiste los componentes básicos para la administración del enfoque del teclado:
- Objetivo de enfoque
- Recorrido de enfoque
Puedes controlar el orden de recorrido del enfoque con los siguientes modificadores de Compose:
- El modificador
focusGroup
- El modificador
focusProperties
Implementaste el patrón típico de UX con teclado físico, enfoque inicial y restablecimiento del enfoque. Estos patrones se implementan combinando las siguientes APIs:
- Clase
FocusRequester
- El modificador
focusRequester
- El modificador
focusRestorer
- Función de componibilidad
LaunchedEffect
La UX implementada se puede probar con pruebas de instrumentación. Compose ofrece formas de presionar teclas y probar si un SemanticsNode
tiene el enfoque del teclado o no.