Las tarjetas pueden hacer más que solo mostrar información; también pueden ser interactivas.
Para que un elemento como textButton()
responda a los toques, genera un controlador de clics con clickable()
y asócialo con el elemento de diseño.
Puedes configurar un Clickable
para activar una acción de dos maneras principales:
- Inicia una actividad directamente: Usa
launchAction()
en los casos en los que necesites abrir una actividad de inmediato. - Delega a tu servicio de tarjetas: Usa
loadAction()
para activar la lógica dentro de tuTileService
. Este es un enfoque más flexible que te permite actualizar el contenido de la tarjeta, actualizar su estado o iniciar una actividad más compleja.
Cómo iniciar una actividad exportada
Si el toque de un usuario debe iniciar una actividad de inmediato, usa launchAction()
.
Proporciona un ComponentName
para identificar la actividad. La actividad se debe exportar. Con este enfoque, puedes pasar extras Intent
con la acción.
Sin embargo, no es posible establecer marcas Intent
personalizadas.
En el siguiente ejemplo, se muestra cómo crear un Clickable
para iniciar TileActivity
con dos elementos adicionales, name
y age
:
textButton( labelContent = { text("launchAction()".layoutString, typography = BODY_LARGE) }, onClick = clickable( action = launchAction( ComponentName( "com.example.wear", "com.example.wear.snippets.m3.tile.TileActivity", ), mapOf( "name" to ActionBuilders.stringExtra("Bartholomew"), "age" to ActionBuilders.intExtra(21), ), ) ), )
Dentro de la actividad iniciada, recupera los valores de los extras del intent:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // When this activity is launched from the tile InteractionLaunchAction, // "name" will be "Bartholomew" and "age" will be 21 val name = intent.getStringExtra("name") val age = intent.getStringExtra("age") // ... }
Controla las interacciones en tu servicio de tarjetas
Para interacciones más flexibles, usa loadAction()
. Cuando un usuario presiona un elemento configurado con loadAction
, el sistema vuelve a invocar tu TileService.onTileRequest()
. Esto te permite ejecutar lógica en tu servicio para actualizar la tarjeta, cambiar su estado y realizar tareas más complejas.
Cómo actualizar el contenido de la tarjeta
El uso más sencillo de loadAction
es indicar una actualización. Llama a loadAction
sin argumentos. Cuando se presiona, el sistema llama a onTileRequest()
, lo que permite que tu servicio devuelva un diseño nuevo con contenido actualizado.
textButton( onClick = clickable(loadAction()), labelContent = { text("Refresh".layoutString) }, )
Distingue entre varios elementos interactivos
Si tu tarjeta contiene varios elementos interactivos, puedes asociar un ID con el modificador Clickable
:
textButton( labelContent = { text("Deep Link me!".layoutString, typography = BODY_LARGE) }, onClick = clickable(id = "foo", action = loadAction()), )
Dentro de onTileRequest()
, puedes verificar este ID con requestParams.currentState.lastClickableId
para decidir qué acción realizar.
Ejemplo: Cómo iniciar una actividad con un vínculo directo
Este patrón es ideal para iniciar una actividad con un vínculo directo. Cuando el usuario presiona la tarjeta para volver a cargarla, tu servicio inspecciona el ID y, luego, inicia la actividad nueva. Para controlar la pila de actividades, usa un TaskStackBuilder
para proporcionar una mejor experiencia de navegación al usuario. Cuando el usuario presiona el elemento, se lo dirige directamente a la pantalla de vínculo directo (la pantalla message_detail/1
del ejemplo). Como se usó .addNextIntentWithParentStack()
, la actividad superior también se agrega a la pila de actividades. Esto significa que, si el usuario desliza el dedo hacia atrás, navegará hasta la pantalla principal de la app (MessageList
en el ejemplo) en lugar de salir inmediatamente a la tarjeta. Si se vuelve a deslizar el dedo hacia atrás, se vuelve a la tarjeta.
override fun onTileRequest( requestParams: RequestBuilders.TileRequest ): ListenableFuture<Tile?> { val lastClickableId = requestParams.currentState.lastClickableId if (lastClickableId == "foo") { TaskStackBuilder.create(this) .addNextIntentWithParentStack( Intent( Intent.ACTION_VIEW, "googleandroidsnippets://app/message_detail/1".toUri(), this, TileActivity::class.java, ) ) .startActivities() } // ... User didn't tap a button (either first load or tapped somewhere else) // ... }
Luego, en TileActivity
, configura la navegación para que coincida con el patrón googleandroidsnippets://app/message_detail/{id}
.
AppScaffold { val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list", ) { // ... composable( route = "message_detail/{id}", deepLinks = listOf( navDeepLink { uriPattern = "googleandroidsnippets://app/message_detail/{id}" } ), ) { val id = it.arguments?.getString("id") ?: "0" MessageDetails(details = "message $id") } } }
Usa TaskStackBuilder
para brindar una mejor experiencia de navegación al usuario.
Cuando el usuario presiona el elemento, se lo dirige directamente a la pantalla de vinculación directa, que, en este ejemplo, es la pantalla message_detail/1
. Debido a que se usó .addNextIntentWithParentStack()
, la actividad superior también se agrega a la pila de actividades. Esto significa que, si el usuario desliza el dedo hacia atrás, navegará hasta la pantalla principal de la app (MessageList
en el ejemplo) en lugar de salir inmediatamente a la tarjeta. Si se desliza el dedo hacia atrás por segunda vez, se vuelve a la tarjeta.
Cómo actualizar el estado de la tarjeta
Tu tarjeta tiene un objeto StateBuilders.State
que almacena pares clave-valor y persiste en las cargas. Puedes usar loadAction()
para actualizar este estado cuando un usuario interactúa con la tarjeta.
Para ello, pasa un DynamicDataMap
a loadAction()
que contenga los valores de estado nuevos.
textButton( labelContent = { text("loadAction()".layoutString, typography = BODY_LARGE) }, onClick = clickable( action = loadAction( dynamicDataMapOf( stringAppDataKey("name") mapTo "Javier", intAppDataKey("age") mapTo 37, ) ) ), )
Cuando esta acción activa onTileRequest()
, puedes leer los datos actualizados de requestParams.currentState.stateMap
. Esto es útil para las interacciones que modifican directamente los datos de la tarjeta, como incrementar un contador o activar un parámetro de configuración.
override fun onTileRequest( requestParams: RequestBuilders.TileRequest ): ListenableFuture<Tile> { // When triggered by loadAction(), "name" will be "Javier", and "age" will // be 37. with(requestParams.currentState.stateMap) { val name = this[stringAppDataKey("name")] val age = this[intAppDataKey("age")] } // ... }