يمكن أن تؤدي المربّعات أكثر من مجرد عرض المعلومات، ويمكن أن تكون تفاعلية أيضًا.
لجعل عنصر مثل textButton()
يستجيب للنقرات، أنشئ معالجًا للنقر باستخدام clickable()
واربطه بعنصر التنسيق.
يمكنك ضبط Clickable
لبدء إجراء بطريقتَين رئيسيتين:
- بدء نشاط مباشرةً: استخدِم
launchAction()
في الحالات التي تحتاج فيها إلى فتح نشاط على الفور. - تفويض خدمة مربّعات البيانات: استخدِم
loadAction()
لتشغيل المنطق داخلTileService
. وهذا الأسلوب أكثر مرونة، إذ يتيح لك تحديث محتوى المربّع أو تعديل حالته أو بدء نشاط أكثر تعقيدًا.
تشغيل نشاط تم تصديره
إذا كان من المفترض أن يؤدي نقر المستخدم إلى بدء نشاط على الفور، استخدِم الرمز launchAction()
.
قدِّم ComponentName
لتحديد النشاط. يجب
تصدير النشاط. باستخدام هذا النهج، يمكنك تمرير 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
:
textButton( labelContent = { text("Deep Link me!".layoutString, typography = BODY_LARGE) }, onClick = clickable(id = "foo", action = loadAction()), )
في onTileRequest()
، يمكنك التحقّق من رقم التعريف هذا باستخدام
requestParams.currentState.lastClickableId
لتحديد الإجراء الذي يجب اتّخاذه.
مثال: بدء نشاط باستخدام رابط لصفحة في التطبيق
هذا النمط مثالي لبدء نشاط باستخدام رابط لصفحة معيّنة. يؤدي انقر المستخدم إلى إعادة تحميل المربّع، وتفحص خدمتك رقم التعريف، ثم تبدأ النشاط الجديد. للتحكّم في الحزمة الخلفية، استخدِم 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()
يحتوي على قيم
state الجديدة.
textButton( labelContent = { text("loadAction()".layoutString, typography = BODY_LARGE) }, onClick = clickable( action = loadAction( dynamicDataMapOf( stringAppDataKey("name") mapTo "Javier", intAppDataKey("age") mapTo 37, ) ) ), )
عندما يتم تنشيط onTileRequest()
من خلال هذا الإجراء، يمكنك قراءة data
المعدَّلة من 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")] } // ... }