ไทล์ทําได้มากกว่าแค่แสดงข้อมูล แต่ยังโต้ตอบได้ด้วย
หากต้องการให้องค์ประกอบ เช่น textButton()
ตอบสนองต่อการแตะ ให้สร้างตัวแฮนเดิลการคลิกโดยใช้ clickable()
และเชื่อมโยงกับองค์ประกอบเลย์เอาต์
คุณกําหนดค่า Clickable
ให้ทริกเกอร์การดําเนินการได้ 2 วิธีหลัก ดังนี้
- เปิดกิจกรรมโดยตรง: ใช้
launchAction()
ในกรณีที่คุณต้องเปิดกิจกรรมทันที - มอบสิทธิ์ให้บริการไทล์: ใช้
loadAction()
เพื่อเรียกใช้ตรรกะภายในTileService
วิธีนี้เป็นวิธีที่ยืดหยุ่นมากขึ้น ซึ่งช่วยให้คุณรีเฟรชเนื้อหาของการ์ด อัปเดตสถานะ หรือเปิดใช้งานกิจกรรมที่ซับซ้อนมากขึ้นได้
เปิดกิจกรรมที่ส่งออก
หากการแตะของผู้ใช้ควรเปิดใช้งานกิจกรรมทันที ให้ใช้ launchAction()
ระบุ ComponentName
เพื่อระบุกิจกรรม ต้องส่งออกกิจกรรม วิธีการนี้ช่วยให้คุณส่งข้อมูลเพิ่มเติม Intent
รายการไปกับการดำเนินการได้
อย่างไรก็ตาม คุณจะตั้งค่า Flag Intent
ที่กำหนดเองไม่ได้
ตัวอย่างต่อไปนี้แสดงวิธีสร้าง Clickable
เพื่อเปิด TileActivity
พร้อมด้วย Extra 2 รายการ ได้แก่ 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), ), ) ), )
ในกิจกรรมที่เปิด ให้ดึงค่าจากข้อมูลเสริมของ 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") // ... }
จัดการการโต้ตอบในบริการข้อมูลแผนที่
หากต้องการการโต้ตอบที่ยืดหยุ่นมากขึ้น ให้ใช้ loadAction()
เมื่อผู้ใช้แตะองค์ประกอบที่กําหนดค่าด้วย loadAction
ระบบจะเรียกใช้ TileService.onTileRequest()
อีกครั้ง ซึ่งจะช่วยให้คุณเรียกใช้ตรรกะในบริการเพื่ออัปเดตการ์ด เปลี่ยนสถานะ และทํางานที่ซับซ้อนมากขึ้นได้
รีเฟรชเนื้อหาของการ์ด
การใช้ loadAction
ที่ง่ายที่สุดคือส่งสัญญาณการรีเฟรช เรียก loadAction
โดยไม่มีอาร์กิวเมนต์ เมื่อแตะ ระบบจะเรียก onTileRequest()
ซึ่งจะช่วยให้บริการแสดงเลย์เอาต์ใหม่ที่มีเนื้อหาที่อัปเดต
textButton( onClick = clickable(loadAction()), labelContent = { text("Refresh".layoutString) }, )
แยกแยะองค์ประกอบแบบอินเทอร์แอกทีฟหลายรายการ
หากการ์ดมีองค์ประกอบแบบอินเทอร์แอกทีฟหลายรายการ คุณสามารถเชื่อมโยงรหัสกับตัวแก้ไข Clickable
ได้โดยทำดังนี้
textButton( labelContent = { text("Deep Link me!".layoutString, typography = BODY_LARGE) }, onClick = clickable(id = "foo", action = loadAction()), )
ใน onTileRequest()
คุณสามารถตรวจสอบรหัสนี้โดยใช้
requestParams.currentState.lastClickableId
เพื่อตัดสินใจว่าจะดำเนินการใดต่อไป
ตัวอย่าง: การเริ่มกิจกรรมด้วย Deep Link
รูปแบบนี้เหมาะสําหรับการเปิดใช้งานกิจกรรมด้วย Deep Link ผู้ใช้แตะโหลดการ์ดอีกครั้ง บริการจะตรวจสอบรหัส แล้วเปิดกิจกรรมใหม่ หากต้องการควบคุมกองซ้อนที่ย้อนกลับ ให้ใช้ TaskStackBuilder
เพื่อให้ผู้ใช้ได้รับประสบการณ์การนําทางที่ดียิ่งขึ้น เมื่อผู้ใช้แตะองค์ประกอบ ระบบจะนำผู้ใช้ไปยังหน้าจอที่ทำ Deep Link โดยตรง (หน้าจอ message_detail/1
จากตัวอย่าง) เนื่องจากมีการใช้ .addNextIntentWithParentStack()
ระบบจึงเพิ่มกิจกรรมหลักลงในกองซ้อนที่ซ้อนกันด้วย ซึ่งหมายความว่าหากผู้ใช้ปัดย้อนกลับ ระบบจะนําทางผู้ใช้ไปยังหน้าจอหลักของแอป (MessageList
ในตัวอย่าง) แทนที่จะออกจากการ์ดทันที การปัดกลับครั้งที่ 2 จะส่งผู้ใช้กลับไปที่การ์ด
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
เพื่อให้ผู้ใช้ได้รับประสบการณ์การนําทางที่ดียิ่งขึ้น
เมื่อผู้ใช้แตะองค์ประกอบ ระบบจะนำผู้ใช้ไปยังหน้าจอที่ทำ Deep Link โดยตรง ซึ่งในตัวอย่างนี้คือหน้าจอ message_detail/1
เนื่องจากมีการใช้ .addNextIntentWithParentStack()
ระบบจึงเพิ่มกิจกรรมหลักลงในกองซ้อนด้านหลังด้วย ซึ่งหมายความว่าหากผู้ใช้ปัดกลับ ระบบจะนําทางผู้ใช้ขึ้นไปยังหน้าจอหลักของแอป (MessageList
ในตัวอย่าง) แทนที่จะออกจากการ์ดทันที การปัดกลับครั้งที่ 2 จะส่งผู้ใช้กลับไปที่การ์ด
อัปเดตสถานะภายในการ์ด
ไทล์ของคุณมีออบเจ็กต์ 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")] } // ... }