功能块不仅可以显示信息,还可以进行互动。
如需使 textButton()
等元素响应点按,请使用 clickable()
生成点击处理脚本,并将其与布局元素相关联。
您可以通过以下两种主要方式配置 Clickable
以触发操作:
- 直接启动 activity:在需要立即打开 activity 的情况下,请使用
launchAction()
。 - 委托给功能块服务:使用
loadAction()
在TileService
中触发逻辑。这种方法更灵活,可让您刷新功能块的内容、更新其状态或启动更复杂的 activity。
启动导出的 activity
如果用户点按应立即启动 activity,请使用 launchAction()
。提供 ComponentName
以标识 activity。activity 必须导出。通过这种方法,您可以通过操作传递 Intent
extra。不过,无法设置自定义 Intent
标志。
以下示例展示了如何创建 Clickable
以使用两个 extra(name
和 age
)启动 TileActivity
:
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), ), ) ), )
在已启动的 activity 内,从 intent extra 中检索值:
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) }, )
区分多个互动元素
如果功能块包含多个互动元素,您可以将 ID 与 Clickable
修饰符相关联:
textButton( labelContent = { text("Deep Link me!".layoutString, typography = BODY_LARGE) }, onClick = clickable(id = "foo", action = loadAction()), )
在 onTileRequest()
中,您可以使用 requestParams.currentState.lastClickableId
检查此 ID,以确定要执行哪项操作。
示例:使用深层链接启动 activity
此模式非常适合使用深层链接启动 activity。用户点按重新加载功能块,您的服务会检查 ID,然后启动新的 activity。如需控制返回堆栈,请使用 TaskStackBuilder
为用户提供更好的导航体验。用户点按该元素后,会直接进入深层链接的屏幕(示例中的 message_detail/1
屏幕)。由于使用了 .addNextIntentWithParentStack()
,因此父 activity 也会添加到返回堆栈中。这意味着,如果用户滑回,则会向上导航到应用的主屏幕(在示例中为 MessageList
),而不是立即退出到功能块。再次滑回可返回到功能块。
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) // ... }
然后,在 TileActivity
中,将导航配置为与 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") } } }
使用 TaskStackBuilder
为用户提供更好的导航体验。
用户点按该元素后,会直接进入深层链接的屏幕(在此示例中,就是 message_detail/1
屏幕)。由于使用了 .addNextIntentWithParentStack()
,因此父 activity 也会添加到返回堆栈中。这意味着,如果用户滑回,则会向上导航到应用的主屏幕(在示例中为 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")] } // ... }