Как взаимодействовать с карточками

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

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

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

Как запустить экспортированное действие

Если нажатие должно немедленно запустить действие, используйте launchAction(). Укажите ComponentName, чтобы идентифицировать действие. Объект activity нужно экспортировать. В этом случае с действием можно передать Intent дополнительных параметров. Однако задавать собственные флаги 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(), чтобы обновить это состояние, когда пользователь взаимодействует с карточкой.

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

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

    // ...
}