המשבצות יכולות לעשות יותר מאשר להציג מידע, הן יכולות גם להיות אינטראקטיביות.
כדי לגרום לרכיב כמו 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
כדי להחליט איזו פעולה לבצע.
דוגמה: הפעלת פעילות באמצעות קישור עומק
התבנית הזו אידיאלית להפעלת פעילות באמצעות קישור עומק. המשתמש מכה על המשבצת כדי לטעון מחדש את המשבצת, השירות בודק את המזהה ומפעיל את הפעילות החדשה. כדי לשלוט ב-back stack, משתמשים ב-TaskStackBuilder
כדי לספק למשתמשים חוויית ניווט טובה יותר. כשהמשתמש מקייש על הרכיב, הוא מועבר ישירות למסך של קישור העומק (המסך message_detail/1
מהדוגמה). מכיוון שנעשה שימוש ב-.addNextIntentWithParentStack()
, גם הפעילות של ההורה מתווספת ל-back stack. כלומר, אם המשתמש מחליק לאחור, הוא יעבור למסך הראשי של האפליקציה (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()
, גם הפעילות ההורה מתווספת ל-back stack. כלומר, אם המשתמש מחליק חזרה, הוא מנווט למסך הראשי של האפליקציה – 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")] } // ... }