כדי להתחיל לספק משבצות מהאפליקציה, צריך לכלול את יחסי התלות הבאים בקובץ build.gradle
של האפליקציה.
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.5.0-alpha04" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.3.0-alpha04" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.3.0-alpha04" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0-alpha04" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.5.0-alpha04" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.5.0-alpha04") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.3.0-alpha04") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.3.0-alpha04") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.5.0-alpha04") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.5.0-alpha04") }
מושגים מרכזיים
המשבצות לא נוצרות באותו אופן שבו נוצרות אפליקציות ל-Android, והן מבוססות על מושגים שונים:
- תבניות פריסה: הגדרת הסדר הכללי של הרכיבים החזותיים במסך. משבצת משתמשת בתבנית פריסה של
EdgeContentLayout
, שכוללת מדד התקדמות מסביב לקצה המסך, או ב-PrimaryLayout
, שלא מציג את המדד הזה. - רכיבי פריסה: מייצגים אלמנט גרפי בודד, כמו
Button
אוChip
, או כמה אלמנטים כאלה שמקובצים יחד באמצעותColumn
, MultiButtonLayout
, MultiSlotLayout
או רכיב דומה. הם מוטמעים בתבנית פריסה. - משאבים: אובייקטים מסוג
ResourceBuilders.Resources
מורכבים ממפה של צמדי מפתח/ערך של משאבי Android (תמונות) שנדרשים לעיבוד (רנדור) של פריסה, וגרסה. - ציר זמן: אובייקט
TimelineBuilders.Timeline
הוא רשימה של מופע אחד או יותר של אובייקט פריסה. אפשר לספק מנגנונים וביטויים שונים כדי לציין מתי ה-Renderer צריך לעבור מאובייקט פריסה אחד לאחר, למשל כדי להפסיק להציג פריסה בשעה מסוימת. - מצב: מבנה נתונים מסוג
StateBuilders.State
שמועברים בין המשבצת לאפליקציה, כדי לאפשר לשני הרכיבים לתקשר ביניהם. לדוגמה, אם מקישים על לחצן באריח, המצב מכיל את המזהה של הלחצן. אפשר גם להמיר בין סוגי נתונים באמצעות מפה. - משבצת: אובייקט
TileBuilders.Tile
שמייצג משבצת, ומורכב מציר זמן, מזהה גרסה של משאבים, מרווח זמן עדכניות ומצב. - Protolayout: המונח הזה מופיע בשם של כיתות שונות שקשורות לאריחים, והוא מתייחס לספריית Protolayout של Wear OS, ספריית גרפיקה שמשמשת בממשקים שונים של Wear OS.
יצירת משבצת
כדי לספק משבצת מהאפליקציה, מטמיעים שירות מסוג TileService
ומירשם אותו במניפסט. על סמך המידע הזה, המערכת מבקשת את המשבצות הנדרשות במהלך קריאות ל-onTileRequest()
ואת המשאבים במהלך קריאות ל-onTileResourcesRequest()
.
class MyTileService : TileService() { override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, "Hello World!") .setTypography(Typography.TYPOGRAPHY_BODY1) .setColor(argb(0xFFFFFFFF.toInt())) .build() ) ) .build() ) override fun onTileResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture( Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ) }
בשלב הבא, מוסיפים שירות בתוך התג <application>
בקובץ AndroidManifest.xml
.
<service android:name=".snippets.tile.MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:icon="@mipmap/ic_launcher" android:exported="true" android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> <intent-filter> <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" /> </intent-filter> <meta-data android:name="androidx.wear.tiles.PREVIEW" android:resource="@drawable/tile_preview" /> </service>
מסנן ההרשאות והכוונות רושם את השירות הזה כספק משבצות.
הסמל, התווית, התיאור והמשאב של התצוגה המקדימה מוצגים למשתמש כשהוא מגדיר את כרטיסי המידע בטלפון או בשעון.
פורסים את האפליקציה ומוסיפים את המשבצת לקרוסלה של המשבצות (יש גם דרך ידידותית יותר למפתחים להציג תצוגה מקדימה של משבצת, אבל בינתיים פשוט עושים את זה באופן ידני).
איור 1. משבצת 'Hello World'.
לדוגמה מלאה, אפשר לעיין בקוד לדוגמה ב-GitHub או בcodelab.
יצירת ממשק משתמש לאריחים
פריסת המשבצת נכתבת באמצעות תבנית build. הפריסה של המשבצת מורכבת מעץ שמכיל קונטיינרים של פריסה ורכיבי פריסה בסיסיים. לכל רכיב פריסה יש מאפיינים שאפשר להגדיר באמצעות שיטות שונות להגדרת מאפיינים.
רכיבי פריסה בסיסיים
יש תמיכה ברכיבים החזותיים הבאים מהספרייה protolayout
, יחד עם רכיבי Material:
Text
: הפיכת מחרוזת טקסט לתמונה, עם אפשרות לגלישת הטקסט.Image
: עיבוד תמונה.Spacer
: רכיב שמספק ריפוד בין רכיבים, או יכול לשמש כמפריד כשמגדירים את צבע הרקע שלו.
רכיבי חומר
בנוסף לרכיבים הבסיסיים, הספרייה protolayout-material
מספקת רכיבים שמאפשרים ליצור עיצוב של משבצות בהתאם להמלצות לממשק המשתמש של Material Design.
Button
: רכיב עגול שניתן ללחוץ עליו, שנועד להכיל סמל.Chip
: רכיב בצורת אצטדיון שניתן ללחוץ עליו, שנועד להכיל עד שני שורות טקסט וסמל אופציונלי.CompactChip
: רכיב בצורת אצטדיון שניתן ללחוץ עליו, שנועד להכיל שורה של טקסט.TitleChip
: רכיב בצורת אצטדיון שניתן ללחוץ עליו, בדומה לרכיבChip
, אבל עם גובה גדול יותר כדי להכיל טקסט של שם.CircularProgressIndicator
: אינדיקטור של התקדמות מעגלית שאפשר למקם בתוךEdgeContentLayout
כדי להציג את ההתקדמות בקצוות המסך.
קונטיינרים של פריסה
אפשר להשתמש בקונטיינרים הבאים, יחד עם פריסות Material:
Row
: הצגת רכיבי הצאצאים באופן אופק, אחד אחרי השני.Column
: הרכיבים הצאצאים מוצגים אנכית, אחד אחרי השני.Box
: שכבות-על של רכיבי הצאצאים זה על גבי זה.Arc
: הצבת רכיבי הצאצאים במעגל.Spannable
: החלתFontStyles
ספציפי על קטעי טקסט, יחד עם החלפת טקסט ותמונות. מידע נוסף זמין במאמר Spannables.
כל קונטיינר יכול להכיל צאצא אחד או יותר, שגם הם יכולים להיות קונטיינרים. לדוגמה, רכיב Column
יכול להכיל כמה רכיבי Row
בתור צאצאים, וכך ליצור פריסה שדומה לחלוקה לרשת.
לדוגמה, משבצת עם פריסה של קונטיינר ושני רכיבי פריסה של צאצאים עשויה להיראות כך:
Kotlin
private fun myLayout(): LayoutElement = Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VERTICAL_ALIGN_BOTTOM) .addContent(Text.Builder() .setText("Hello world") .build() ) .addContent(Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build()
Java
private LayoutElement myLayout() { return new Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_BOTTOM) .addContent(new Text.Builder() .setText("Hello world") .build() ) .addContent(new Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build(); }
פריסות של Material
בנוסף לפריסות בסיסיות, בספרייה protolayout-material
יש כמה פריסות מוגדרות מראש שנועדו להכיל רכיבים ב'משבצות' ספציפיות.
PrimaryLayout
: מיקום של פעולה ראשית אחתCompactChip
בתחתית המסך, עם התוכן במרכז מעליו.MultiSlotLayout
: ממקם תוויות ראשיות ומשניות עם תוכן אופציונלי ביניהן, וCompactChip
אופציונלי בתחתית המסך.MultiButtonLayout
: ממקם קבוצת לחצנים שמסודרים בהתאם להנחיות של Material.EdgeContentLayout
: ממקם תוכן סביב קצה המסך, למשלCircularProgressIndicator
. כשמשתמשים בפריסה הזו, התוכן שבתוכה מקבל באופן אוטומטי את השוליים והרווחים המתאימים.
קשתות
יש תמיכה בצאצאים הבאים של קונטיינר Arc
:
ArcLine
: יוצר קו מעוקל סביב ה-Arc.ArcText
: עיבוד טקסט מעוקל ב-Arc.ArcAdapter
: המערכת תיצור עיבוד של אלמנט פריסה בסיסי בתוך קשת, שתוחם את הקשת.
מידע נוסף זמין במאמרי העזרה של כל אחד מסוגי הרכיבים.
גורמי שינוי
אפשר להחיל משתני אופן פעולה על כל אלמנט פריסה זמין. אפשר להשתמש במקשי השינוי האלה למטרות הבאות:
- שינוי המראה החזותי של הפריסה. לדוגמה, מוסיפים רקע, גבול או ריפוד לאלמנט הפריסה.
- מוסיפים מטא-נתונים לגבי הפריסה. לדוגמה, אפשר להוסיף רכיב לשינוי סמנטיקה לרכיב הפריסה לשימוש עם קוראי מסך.
- הוספת פונקציונליות. לדוגמה, אפשר להוסיף רכיב שינוי שאפשר ללחוץ עליו לרכיב הפריסה כדי להפוך את המשבצת לאינטראקטיבית. מידע נוסף זמין במאמר אינטראקציה עם משבצות.
לדוגמה, אפשר להתאים אישית את המראה והמטא-נתונים שמוגדרים כברירת מחדל של Image
, כפי שמתואר בקטע הקוד הבא:
Kotlin
private fun myImage(): LayoutElement = Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(Modifiers.Builder() .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(Padding.Builder().setStart(dp(12f)).build()) .setSemantics(Semantics.builder() .setContentDescription("Image description") .build() ).build() ).build()
Java
private LayoutElement myImage() { return new Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(new Modifiers.Builder() .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(new Padding.Builder().setStart(dp(12f)).build()) .setSemantics(new Semantics.Builder() .setContentDescription("Image description") .build() ).build() ).build(); }
מודעות Spannable
Spannable
הוא סוג מיוחד של מאגר שמציג את הרכיבים באופן דומה לזה שבו מוצג טקסט. האפשרות הזו שימושית כשרוצים להחיל סגנון שונה רק על מחרוזת משנה אחת בבלוק טקסט גדול יותר, דבר שלא ניתן לעשות באמצעות הרכיב Text
.
קונטיינר Spannable
מלא בצאצאים מסוג Span
. אסור להשתמש בילדים אחרים או במופעי Spannable
בתצוגת עץ.
יש שני סוגים של צאצאים של Span
:
לדוגמה, אפשר להדגיש את המילה 'world' בכותרת 'Hello world' ולהוסיף תמונה בין המילים, כמו בקטע הקוד הבא:
Kotlin
private fun mySpannable(): LayoutElement = Spannable.Builder() .addSpan(SpanText.Builder() .setText("Hello ") .build() ) .addSpan(SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(SpanText.Builder() .setText("world") .setFontStyle(FontStyle.Builder() .setItalic(true) .build()) .build() ).build()
Java
private LayoutElement mySpannable() { return new Spannable.Builder() .addSpan(new SpanText.Builder() .setText("Hello ") .build() ) .addSpan(new SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(new SpanText.Builder() .setText("world") .setFontStyle(newFontStyle.Builder() .setItalic(true) .build()) .build() ).build(); }
עבודה עם משאבים
לכרטיסי המידע אין גישה למשאבים של האפליקציה. המשמעות היא שאי אפשר להעביר מזהה תמונה של Android לרכיב פריסה מסוג Image
ולצפות שהוא יפתור את הבעיה. במקום זאת, צריך לשנות את השיטה onTileResourcesRequest()
ולספק את המשאבים באופן ידני.
יש שתי דרכים לספק תמונות בתוך השיטה onTileResourcesRequest()
:
- מספקים משאב שאפשר לצייר באמצעות
setAndroidResourceByResId()
. - מספקים תמונה דינמית כ-
ByteArray
באמצעותsetInlineResource()
.
Kotlin
override fun onTileResourcesRequest( requestParams: ResourcesRequest ) = Futures.immediateFuture( Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", ImageResource.Builder() .setAndroidResourceByResId(AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", ImageResource.Builder() .setInlineResource(InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() )
Java
@Override protected ListenableFuture<Resources> onTileResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture( new Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", new ImageResource.Builder() .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", new ImageResource.Builder() .setInlineResource(new InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() ); }
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מעבר למרחבי שמות של ProtoLayout
ConstraintLayout
ב-Compose- יצירת משבצות בהתאמה אישית של הגדרות מהירות לאפליקציה