Взаимодействуйте с плитками

Плитки могут делать больше, чем просто отображать информацию; они также могут быть интерактивными. Чтобы элемент, такой как textButton() реагировал на нажатия, сгенерируйте обработчик щелчков с помощью clickable() и свяжите его с элементом макета.

Вы можете настроить Clickable для запуска действия двумя основными способами:

  1. Запустите действие напрямую : используйте launchAction() в случаях, когда вам нужно немедленно открыть действие.
  2. Делегируйте своей службе плиток : используйте loadAction() для запуска логики в вашей TileService . Это более гибкий подход, который позволяет вам обновлять содержимое плитки, обновлять ее состояние или запускать более сложную активность.

Запуск экспортируемой деятельности

Если нажатие пользователя должно немедленно запустить действие, используйте launchAction() . Укажите ComponentName для идентификации действия. Действие должно быть экспортировано . При таком подходе вы можете передавать Intent extras с действием. Однако невозможно установить пользовательские флаги Intent .

В следующем примере показано, как создать Clickable для запуска TileActivity с двумя дополнительными данными: name и 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),
            ),
        )
    ),
)

Внутри запущенной активности извлеките значения из дополнительных намерений:

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")

    // ...
}

Управляйте взаимодействиями в вашем сервисе по плитке

Для более гибких взаимодействий используйте loadAction() . Когда пользователь нажимает на элемент, настроенный с помощью loadAction , система повторно вызывает ваш TileService.onTileRequest() . Это позволяет вам запускать логику в вашей службе для обновления плитки, изменения ее состояния и выполнения более сложных задач.

Обновить содержимое плитки

Простейшее использование loadAction — сигнализировать об обновлении. Вызовите loadAction без аргументов. При нажатии система вызывает onTileRequest() , позволяя вашей службе вернуть новый макет с обновленным содержимым.

textButton(
    onClick = clickable(loadAction()),
    labelContent = { text("Refresh".layoutString) },
)

Различать несколько интерактивных элементов

Если ваша плитка содержит несколько интерактивных элементов, вы можете связать идентификатор с модификатором Clickable :

Внутри onTileRequest() вы можете проверить этот идентификатор с помощью requestParams.currentState.lastClickableId , чтобы решить, какое действие выполнить.

Пример: запуск действия с глубокой ссылкой

Этот шаблон идеально подходит для запуска действия с глубокой ссылкой . Касание пользователя перезагружает плитку, ваш сервис проверяет идентификатор, а затем запускает новое действие. Чтобы управлять стеком переходов назад, используйте TaskStackBuilder , чтобы обеспечить пользователю лучшую навигацию. Когда пользователь касается элемента, он перенаправляется непосредственно на экран с глубокой ссылкой (экран message_detail/1 из примера). Поскольку использовался .addNextIntentWithParentStack() , родительское действие также добавляется в стек переходов назад. Это означает, что если пользователь смахнет назад, он перейдет на главный экран приложения ( MessageList в примере) вместо того, чтобы немедленно выйти на плитку. Смахивание назад во второй раз возвращает его на плитку.

Затем в TileActivity настройте навигацию в соответствии с шаблоном googleandroidsnippets://app/message_detail/{id} .

Используйте TaskStackBuilder , чтобы предоставить пользователю лучший опыт навигации. Когда пользователь нажимает на элемент, он сразу попадает на экран с глубокой ссылкой — в этом примере это экран message_detail/1 . Поскольку использовался .addNextIntentWithParentStack() , родительская активность также добавляется в стек возврата. Это означает, что если пользователь смахнет назад, он перейдет на главный экран приложения — MessageList в этом примере — вместо того, чтобы немедленно выйти на плитку. Смахивание назад во второй раз возвращает его на плитку.

Обновить состояние внутри плитки

У вашей плитки есть объект StateBuilders.State , который хранит пары ключ-значение и сохраняется при перезагрузках. Вы можете использовать loadAction() для обновления этого состояния, когда пользователь взаимодействует с плиткой.

Для этого передайте DynamicDataMap в loadAction() содержащий новые значения состояния.

textButton(
    labelContent = {
        text("loadAction()".layoutString, typography = BODY_LARGE)
    },
    onClick =
    clickable(
        action =
        loadAction(
            dynamicDataMapOf(
                stringAppDataKey("name") mapTo "Javier",
                intAppDataKey("age") mapTo 37,
            )
        )
    ),
)

Когда onTileRequest() запускается этим действием, вы можете прочитать обновленные данные из requestParams.currentState.stateMap . Это полезно для взаимодействий, которые напрямую изменяют данные на плитке, например, для увеличения счетчика или переключения настройки.

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")]
    }

    // ...
}
{% дословно %} {% endverbatim %} {% дословно %} {% endverbatim %}