資訊方塊不只會顯示資訊,還能提供互動功能。如要讓 textButton() 等元素回應輕觸動作,請使用 clickable() 產生點擊處理常式,並將其與版面配置元素建立關聯。
您可以透過兩種主要方式設定 Clickable 以觸發動作:
- 直接啟動活動:如果需要立即開啟活動,請使用
launchAction()。 - 委派至資訊方塊服務:使用
loadAction()觸發TileService中的邏輯。這是更具彈性的做法,可讓您重新整理資訊方塊的內容、更新其狀態,或啟動更複雜的活動。
啟動匯出的活動
如果使用者輕觸後應立即啟動活動,請使用 launchAction()。提供 ComponentName 來識別活動。活動必須匯出。使用這個方法,您可以透過動作傳遞 Intent 額外項目。不過,您無法設定自訂 Intent 標記。
以下範例說明如何建立 Clickable,以便透過兩個額外項目 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), ), ) ), )
在啟動的活動中,從意圖額外項目擷取值:
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 修飾符將 ID 關聯:
textButton( labelContent = { text("Deep Link me!".layoutString, typography = BODY_LARGE) }, onClick = clickable(id = "foo", action = loadAction()), )
在 onTileRequest() 中,您可以使用 requestParams.currentState.lastClickableId 檢查此 ID,決定要執行哪些動作。
範例:使用深層連結啟動活動
此模式非常適合使用深層連結啟動活動。使用者輕觸重新載入圖塊,您的服務會檢查 ID,然後啟動新的活動。如要控制返回堆疊,請使用 TaskStackBuilder 為使用者提供更優質的導覽體驗。使用者輕觸元素後,系統會直接將他們導向深層連結畫面 (範例中的 message_detail/1 畫面)。由於使用了 .addNextIntentWithParentStack(),因此父項活動也會新增至返回堆疊。也就是說,如果使用者滑動返回,他們會向上瀏覽應用程式的主畫面 (範例中的 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(),因此父項活動也會新增至返回堆疊。也就是說,如果使用者滑動返回,他們會向上瀏覽應用程式的主畫面 (在本例中為 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")] } // ... }