Cómo interactuar con tarjetas

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:

  1. Inicia una actividad directamente: Usa launchAction() en los casos en los que necesites abrir una actividad de inmediato.
  2. Delega a tu servicio de tarjetas: Usa loadAction() para activar la lógica dentro de tu TileService. 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:

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.

Luego, en TileActivity, configura la navegación para que coincida con el patrón googleandroidsnippets://app/message_detail/{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")]
    }

    // ...
}