במכשירי Wear OS, שני רכיבים מרכזיים עם ניהול גרסאות עצמאיים מבצעים את העיבוד של המשבצות. כדי לוודא שהמשבצות של האפליקציות יפעלו בצורה תקינה בכל המכשירים, חשוב להבין את הארכיטקטורה הבסיסית הזו.
- ספריות שקשורות ל-Jetpack Tiles: הספריות האלה (כולל Wear Tiles ו-Wear ProtoLayout) מוטמעות באפליקציה, ואתם, בתור מפתחים, שולטים בגרסאות שלהן. האפליקציה משתמשת בספריות האלה כדי ליצור אובייקט
TileBuilder.Tile
(מבנה הנתונים שמייצג את המשבצת) בתגובה לקריאהonTileRequest()
של המערכת. - ProtoLayout Renderer: רכיב המערכת הזה אחראי לעיבוד הגרפי של האובייקט
Tile
במסך ולטיפול באינטראקציות של המשתמשים. מפתח האפליקציה לא יכול לשלוט בגרסה של המרת הווידאו, והיא יכולה להשתנות בין מכשירים שונים, גם אם יש להם חומרה זהה.
המראה או ההתנהגות של המשבצת יכולים להשתנות בהתאם לגרסאות של ספריית Jetpack Tiles באפליקציה ולגרסה של ProtoLayout Renderer במכשיר של המשתמש. לדוגמה, מכשיר אחד עשוי לתמוך ברוטציה או בהצגת נתוני דופק, ומכשיר אחר לא.
במסמך הזה נסביר איך לוודא שהאפליקציה תואמת לגרסאות שונות של ספריית Tiles ושל ProtoLayout Renderer, ואיך לעבור לגרסאות מתקדמות יותר של ספריות Jetpack.
התאמה
כדי ליצור משבצת שפועלת בצורה תקינה במגוון מכשירים, כדאי לשקול את הדברים הבאים.
זיהוי גרסת המרינר
- משתמשים בשיטה
getRendererSchemaVersion()
של האובייקטDeviceParameters
שמוענק לשיטה onTileRequest(). השיטה הזו מחזירה את מספרי הגרסה הראשית והמשנית של ה-ProtoLayout Renderer במכשיר. - לאחר מכן תוכלו להשתמש בלוגיקה מותנית בהטמעה של
onTileRequest()
כדי להתאים את העיצוב או ההתנהגות של המשבצת על סמך גרסת המרינר שזוהתה.- לדוגמה, אם אנימציה מסוימת לא נתמכת, תוכלו להציג תמונה סטטית במקום זאת.
ההערה @RequiresSchemaVersion
- ההערה
@RequiresSchemaVersion
בשיטות ProtoLayout מציינת את גרסת הסכימה המינימלית של ה-renderer שנדרשת כדי שהשיטה תתנהג כפי שמתואר (דוגמה).- קריאה ל-method שדורשת גרסת עיבוד תמונה גבוהה יותר מזו שזמינה במכשיר לא תגרום לקריסה של האפליקציה, אבל היא עלולה לגרום לכך שהתוכן לא יוצג או שהתכונה תתעלם.
דוגמה
override fun onTileRequest(
requestParams: TileService.TileRequest
): ListenableFuture<Tile> {
val rendererVersion =
requestParams.deviceConfiguration.rendererSchemaVersion
val tile = Tile.Builder()
if (
rendererVersion.major > 1 ||
(rendererVersion.major == 1 && rendererVersion.minor >= 300)
) {
// Use a feature supported in renderer version 1.300 or later
tile.setTileTimeline(/* ... */ )
} else {
// Provide fallback content for older renderers
tile.setTileTimeline(/* ... */ )
}
return Futures.immediateFuture(tile.build())
}
בדיקה עם גרסאות שונות של המנגן
כדי לבדוק את המשבצות בגרסאות שונות של המרתן, צריך לפרוס אותן בגרסאות שונות של אמולטור Wear OS. (במכשירים פיזיים, עדכוני ה-ProtoLayout Renderer מועברים על ידי חנות Play או עדכוני מערכת. אי אפשר לאלץ התקנה של גרסה ספציפית של המנגן).
התכונה 'תצוגה מקדימה של משבצות' ב-Android Studio משתמשת בנגן מוטמע בספריית Jetpack ProtoLayout שהקוד שלכם תלוי בה. לכן, גישה אחרת היא להסתמך על גרסאות שונות של ספריית Jetpack כשבודקים משבצות.
מעבר ל-Tiles 1.5 או ל-ProtoLayout 1.3 (Material 3 Expressive)
כדאי לעדכן את ספריות Jetpack Tile כדי ליהנות מהשיפורים האחרונים, כולל שינויים בממשק המשתמש שיעזרו לשלב את המשבצות במערכת בצורה חלקה.
ב-Jetpack Tiles 1.5 וב-Jetpack ProtoLayout 1.3 יש כמה שיפורים ושינויים משמעותיים. למשל:
- ממשק API שדומה ל-Compose לתיאור ממשק המשתמש.
- רכיבים של Material 3 Expressive, כולל לחצן קצה שמצמיד את המסך למטה ותמיכה ברכיבים חזותיים משופרים: אנימציות Lottie, סוגים נוספים של פס מודגש וסגנונות חדשים של קווים מעוקלים. - הערה: אפשר להשתמש בחלק מהתכונות האלה גם בלי לעבור ל-API החדש.
המלצות
- העברת כל האריחים בו-זמנית. מומלץ לא לשלב גרסאות של משבצות באפליקציה. רכיבי Material 3 נמצאים בארטיפקט נפרד (
androidx.wear.protolayout:protolayout-material3
), כך שאפשר להשתמש גם במשבצות M2.5 וגם במשבצות M3 באותה אפליקציה. עם זאת, אנחנו ממליצים מאוד לא להשתמש בגישה הזו אלא אם יש צורך בכך באופן מוחלט (לדוגמה, אם יש באפליקציה מספר גדול של משבצות שאי אפשר להעביר את כולן בבת אחת). - יישום ההנחיות בנושא חוויית משתמש של משבצות מכיוון שהקובצי המשבצות הם בעלי מבנה ותבנית קפדניים, מומלץ להשתמש בעיצובים שבדוגמאות הקיימות כנקודות מוצא לעיצובים שלכם.
- כדאי לבדוק את המודעות במגוון גדלים של מסכים וגופנים. לרוב, משבצות מכילות מידע רב, ולכן הטקסט (במיוחד כשהוא ממוקם על לחצנים) עלול לחרוג מהמסגרת או להיחתוך. כדי לצמצם את הזמן הזה, מומלץ להשתמש ברכיבים מוכנים ולהימנע מהתאמה אישית נרחבת. כדאי לבדוק את התצוגה באמצעות התכונה 'תצוגה מקדימה של משבצות' ב-Android Studio וגם במספר מכשירים אמיתיים.
תהליך ההעברה
עדכון יחסי התלות
קודם מעדכנים את הקובץ build.gradle.kts
. מעדכנים את הגרסאות ומשנים את התלות ב-protolayout-material
ל-protolayout-material3
, כפי שמוצג:
// In build.gradle.kts
//val tilesVersion = "1.4.1"
//val protoLayoutVersion = "1.2.1"
// Use these versions for M3.
val tilesVersion = "1.5.0-rc01"
val protoLayoutVersion = "1.3.0-rc01"
dependencies {
// Use to implement support for wear tiles
implementation("androidx.wear.tiles:tiles:$tilesVersion")
// Use to utilize standard components and layouts in your tiles
implementation("androidx.wear.protolayout:protolayout:$protoLayoutVersion")
// Use to utilize components and layouts with Material Design in your tiles
// implementation("androidx.wear.protolayout:protolayout-material:$protoLayoutVersion")
implementation("androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion")
// Use to include dynamic expressions in your tiles
implementation("androidx.wear.protolayout:protolayout-expression:$protoLayoutVersion")
// Use to preview wear tiles in your own app
debugImplementation("androidx.wear.tiles:tiles-renderer:$tilesVersion")
// Use to fetch tiles from a tile provider in your tests
testImplementation("androidx.wear.tiles:tiles-testing:$tilesVersion")
}
שירות TileService לא השתנה במידה רבה
השינויים העיקריים בהעברה הזו משפיעים על רכיבי ממשק המשתמש. כתוצאה מכך, ההטמעה של TileService
, כולל מנגנוני טעינת המשאבים, אמורה לדרוש שינויים מינימליים או לא לדרוש שינויים בכלל.
היוצא מן הכלל העיקרי נוגע למעקב אחר פעילות של משבצות: אם האפליקציה שלכם משתמשת ב-onTileEnterEvent()
או ב-onTileLeaveEvent()
, עליכם לעבור ל-onRecentInteractionEventsAsync()
. החל מ-API 36, האירועים האלה יצורפו לקבוצות.
התאמה של הקוד ליצירת הפריסה
ב-ProtoLayout 1.2 (M2.5), השיטה onTileRequest()
מחזירה TileBuilders.Tile
. האובייקט הזה הכיל רכיבים שונים, כולל TimelineBuilders.Timeline
, שבתורו הכיל את LayoutElement
שמתאר את ממשק המשתמש של המשבצת.
ב-ProtoLayout 1.3 (M3), מבנה הנתונים והתהליך הכללי לא השתנו, אבל ה-LayoutElement
נוצר עכשיו באמצעות גישה בהשראת Compose, עם פריסה שמבוססת על תאים מוגדרים. התאים האלה הם (למעלה למטה) titleSlot
(בדרך כלל לכותרת ראשית או לכותרת), mainSlot
(לתוכן הליבה) ו-bottomSlot
(לרוב לפעולות כמו לחצן קצה או מידע נוסף כמו טקסט קצר). הפריסה הזו נוצרת על ידי הפונקציה primaryLayout()
.

השוואה בין פונקציות של פריסה M2.5 לבין פונקציות של פריסה M3
M2.5
fun myLayout(
context: Context,
deviceConfiguration: DeviceParametersBuilders.DeviceParameters
) =
PrimaryLayout.Builder(deviceConfiguration)
.setResponsiveContentInsetEnabled(true)
.setContent(
Text.Builder(context, "Hello World!")
.setTypography(Typography.TYPOGRAPHY_BODY1)
.setColor(argb(0xFFFFFFFF.toInt()))
.build()
)
.build()
M3
fun myLayout(
context: Context,
deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
) =
materialScope(context, deviceConfiguration) {
primaryLayout(mainSlot = { text("Hello, World!".layoutString) })
}
כדי להדגיש את ההבדלים העיקריים:
- הסרת 'בנאים'. דפוס ה-builder המסורתי לרכיבי ממשק המשתמש של Material3 הוחלף בתחביר דקלרטיבי יותר בהשראת Compose. (גם לרכיבים שאינם ממשק משתמש, כמו String/Color/Modifiers, יש עכשיו חבילות Kotlin חדשות).
- פונקציות סטנדרטיות של פריסת נתונים והפעלה. פריסות M3 מסתמכות על פונקציות סטנדרטיות של מבנה ואתחלה:
materialScope()
ו-primaryLayout()
. הפונקציות החובה האלה מאתחלות את הסביבה של M3 (עיצוב, היקף הרכיבים באמצעותmaterialScope
) ומגדירות את הפריסה הראשית שמבוססת על מודעות (באמצעותprimaryLayout
). צריך להפעיל את שתי הפונקציות בדיוק פעם אחת לכל פריסה.
קביעת עיצוב
צבע
אחת מהתכונות הבולטות של Material 3 Expressive היא 'עיצוב דינמי': משבצות שמפעילות את התכונה הזו (מופעלת כברירת מחדל) יוצגו בעיצוב שסופק על ידי המערכת (הזמינות תלויה במכשיר ובהגדרות של המשתמש).
שינוי נוסף ב-M3 הוא הרחבת מספר האסימונים של הצבעים, שעלה מ-4 ל-29. אסימוני הצבע החדשים נמצאים בכיתה ColorScheme
.
טיפוגרפיה
בדומה ל-M2.5, גם ב-M3 יש שימוש רב בקבועים מוגדרים מראש של גודל גופן – לא מומלץ לציין גודל גופן ישירות. הקבועים האלה נמצאים בכיתה Typography
ומציעים מגוון מורחב מעט של אפשרויות ביטוי.
פרטים מלאים זמינים במסמכי העזרה בנושא טיפוגרפיה.
צורה
רוב הרכיבים מסוג M3 יכולים להשתנות במאפיין הצורה וגם בצבע.
textButton
(ב-mainSlot
) בצורה full
:

אותו textButton עם הצורה small
:

רכיבים
רכיבי M3 גמישים יותר וניתן להגדיר אותם בקלות רבה יותר בהשוואה לרכיבי M2.5. ב-M2.5 נדרשו לעתים קרובות רכיבים נפרדים לטיפולים חזותיים שונים, בעוד שב-M3 נעשה שימוש לעיתים קרובות ברכיב 'בסיס' כללי שניתן להתאמה אישית במידה רבה, עם הגדרות ברירת מחדל טובות.
העיקרון הזה חל על הפריסה ברמה הבסיסית (root). בגרסה M2.5, הערך הזה היה PrimaryLayout
או EdgeContentLayout
. ב-M3, אחרי שמוגדר MaterialScope
יחיד ברמה העליונה, מתבצעת קריאה לפונקציה primaryLayout()
. הפונקציה הזו מחזירה את הפריסה ברמה הבסיסית ישירות (אין צורך ב-builders), והיא מקבלת את הערך LayoutElements
לכמה 'מקומות', כמו titleSlot
, mainSlot
ו-bottomSlot
. אפשר לאכלס את החריצים האלה ברכיבי ממשק משתמש ספציפיים, כמו אלה שמוחזרים על ידי text(), button() או card(), או במבנים של פריסה, כמו Row
או Column
מ-LayoutElementBuilders
.
העיצובים מייצגים שיפור נוסף של M3. כברירת מחדל, רכיבי ממשק המשתמש פועלים בהתאם למפרטי העיצוב של M3 ותומכים בעיצוב דינמי.
M2.5 | M3 |
---|---|
רכיבים אינטראקטיביים | |
Button או Chip |
|
טקסט | |
Text |
text() |
אינדיקטורים של התקדמות | |
CircularProgressIndicator |
circularProgressIndicator() או segmentedCircularProgressIndicator() |
פריסה | |
PrimaryLayout או EdgeContentLayout |
primaryLayout() |
— | buttonGroup() |
תמונות | |
— | icon() , avatarImage() או backgroundImage() |
גורמי שינוי
ב-M3, Modifiers
, שמשמש לקישוט או להוספה של רכיב, דומה יותר ל-Compose. השינוי הזה יכול לצמצם את הקוד הסטנדרטי על ידי יצירה אוטומטית של הסוגים הפנימיים המתאימים. (השינוי הזה לא משפיע על השימוש ברכיבי ממשק המשתמש של M3. במקרה הצורך, אפשר להשתמש במודיפיקרים בסגנון בונה מ-ProtoLayout 1.2 עם רכיבי ממשק המשתמש של M3, ולהפך).
M2.5
// A Builder-style modifier to set the opacity of an element to 0.5
fun myModifier(): ModifiersBuilders.Modifiers =
ModifiersBuilders.Modifiers.Builder()
.setOpacity(TypeBuilders.FloatProp.Builder(0.5F).build())
.build()
M3
// The equivalent Compose-like modifier is much simpler
fun myModifier(): LayoutModifier = LayoutModifier.opacity(0.5F)
אפשר ליצור משתני אופן באמצעות סגנון API כלשהו, ואפשר גם להשתמש בפונקציית התוסף toProtoLayoutModifiers()
כדי להמיר LayoutModifier
ל-ModifiersBuilders.Modifier
.
פונקציות עזר
ב-ProtoLayout 1.3 אפשר להשתמש ברכיבים רבים של ממשק המשתמש באמצעות API בהשראת Compose, אבל רכיבי פריסה בסיסיים כמו שורות ועמודות מ-LayoutElementBuilders
ממשיכים להשתמש בתבנית ה-builder. כדי לגשר על הפער בסגנון ולשמור על עקביות עם ממשקי ה-API החדשים של רכיבי M3, כדאי להשתמש בפונקציות עזר.
ללא עוזרים
primaryLayout(
mainSlot = {
LayoutElementBuilders.Column.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(text("A".layoutString))
.addContent(text("B".layoutString))
.addContent(text("C".layoutString))
.build()
}
)
עם עוזרים
// Function literal with receiver helper function
fun column(builder: Column.Builder.() -> Unit) =
Column.Builder().apply(builder).build()
primaryLayout(
mainSlot = {
column {
setWidth(expand())
setHeight(expand())
addContent(text("A".layoutString))
addContent(text("B".layoutString))
addContent(text("C".layoutString))
}
}
)
מעבר לגרסה 1.2 של Tiles או לגרסה 1.0 של ProtoLayout
החל מגרסה 1.2, רוב ממשקי ה-API של פריסת המשבצות נמצאים במרחב השמות androidx.wear.protolayout
. כדי להשתמש בממשקי ה-API העדכניים ביותר, צריך לבצע את שלבי ההעברה הבאים בקוד.
עדכון יחסי התלות
מבצעים את השינויים הבאים בקובץ ה-build של מודול האפליקציה:
Groovy
// Removeimplementation 'androidx.wear.tiles:tiles-material:version'// Include additional dependencies implementation "androidx.wear.protolayout:protolayout:1.2.1" implementation "androidx.wear.protolayout:protolayout-material:1.2.1" implementation "androidx.wear.protolayout:protolayout-expression:1.2.1" // Update implementation "androidx.wear.tiles:tiles:1.4.1"
Kotlin
// Removeimplementation("androidx.wear.tiles:tiles-material:version")// Include additional dependencies implementation("androidx.wear.protolayout:protolayout:1.2.1") implementation("androidx.wear.protolayout:protolayout-material:1.2.1") implementation("androidx.wear.protolayout:protolayout-expression:1.2.1") // Update implementation("androidx.wear.tiles:tiles:1.4.1")
עדכון מרחבי שמות
מבצעים את העדכונים הבאים בקובצי הקוד של האפליקציה שמבוססים על Kotlin ועל Java. לחלופין, אפשר להריץ את הסקריפט לשינוי שם של מרחב שמות.
- מחליפים את כל הייבוא של
androidx.wear.tiles.material.*
ב-androidx.wear.protolayout.material.*
. צריך להשלים את השלב הזה גם בספרייהandroidx.wear.tiles.material.layouts
. מחליפים את רוב ייבוא ה-
androidx.wear.tiles.*
ב-androidx.wear.protolayout.*
.הייבוא של
androidx.wear.tiles.EventBuilders
,androidx.wear.tiles.RequestBuilders
,androidx.wear.tiles.TileBuilders
ו-androidx.wear.tiles.TileService
לא אמור להשתנות.שינוי השם של כמה שיטות שהוצאו משימוש מהכיתות TileService ו-TileBuilder:
TileBuilders
: מ-getTimeline()
עדgetTileTimeline()
ומ-setTimeline()
עדsetTileTimeline()
TileService
:onResourcesRequest()
עדonTileResourcesRequest()
RequestBuilders.TileRequest
: מ-getDeviceParameters()
עדgetDeviceConfiguration()
, מ-setDeviceParameters()
עדsetDeviceConfiguration()
, מ-getState()
עדgetCurrentState()
ומ-setState()
עדsetCurrentState()