ในอุปกรณ์ Wear OS ไทล์จะแสดงผลโดยคอมโพเนนต์หลัก 2 รายการที่มีเวอร์ชันแยกกัน คุณต้องเข้าใจสถาปัตยกรรมพื้นฐานนี้เพื่อให้การ์ดแอปทำงานได้อย่างถูกต้องในอุปกรณ์ทุกเครื่อง
- ไลบรารีที่เกี่ยวข้องกับการ์ดของ Jetpack: ไลบรารีเหล่านี้ (รวมถึงการ์ด Wear และ Wear ProtoLayout) จะฝังอยู่ในแอปของคุณ และในฐานะนักพัฒนาแอป คุณจะควบคุมเวอร์ชันของไลบรารีได้ แอปของคุณใช้ไลบรารีเหล่านี้เพื่อสร้างออบเจ็กต์
TileBuilder.Tile
(โครงสร้างข้อมูลที่แสดงการ์ด) เพื่อตอบสนองต่อการเรียกใช้onTileRequest()
ของระบบ - โปรแกรมแสดงผล ProtoLayout: คอมโพเนนต์ของระบบนี้มีหน้าที่แสดงผลออบเจ็กต์
Tile
บนจอแสดงผลและจัดการการโต้ตอบของผู้ใช้ นักพัฒนาแอปไม่สามารถควบคุมเวอร์ชันของโปรแกรมแสดงผลได้ และเวอร์ชันดังกล่าวอาจแตกต่างกันไปตามอุปกรณ์ต่างๆ แม้ว่าอุปกรณ์เหล่านั้นจะใช้ฮาร์ดแวร์เดียวกันก็ตาม
ลักษณะที่ปรากฏหรือลักษณะการทํางานของการ์ดอาจแตกต่างกันไปตามทั้งเวอร์ชันไลบรารี Jetpack Tiles ของแอปและเวอร์ชันโปรแกรมแสดงผล ProtoLayout ในอุปกรณ์ของผู้ใช้ เช่น อุปกรณ์หนึ่งอาจรองรับการหมุนหรือการแสดงข้อมูลอัตราการเต้นของหัวใจ แต่อุปกรณ์อีกเครื่องหนึ่งอาจไม่รองรับ
เอกสารนี้จะอธิบายวิธีตรวจสอบว่าแอปของคุณเข้ากันได้กับไลบรารี Tiles และโปรแกรมแสดงผล ProtoLayout เวอร์ชันต่างๆ รวมถึงวิธีย้ายข้อมูลไปยังไลบรารี Jetpack เวอร์ชันที่ใหม่กว่า
พิจารณาความเข้ากันได้
หากต้องการสร้างการ์ดที่ทำงานได้อย่างถูกต้องในอุปกรณ์ต่างๆ คุณควรพิจารณาสิ่งต่อไปนี้
ตรวจหาเวอร์ชันโปรแกรมแสดงผล
- ใช้เมธอด
getRendererSchemaVersion()
ของออบเจ็กต์DeviceParameters
ที่ส่งไปยังเมธอด onTileRequest() เมธอดนี้จะแสดงหมายเลขเวอร์ชันหลักและรองของ ProtoLayout Renderer ในอุปกรณ์ - จากนั้นคุณก็ใช้ตรรกะแบบมีเงื่อนไขใน
onTileRequest()
การติดตั้งใช้งานเพื่อปรับการออกแบบหรือลักษณะการทํางานของการ์ดตามเวอร์ชันโปรแกรมแสดงผลที่ตรวจพบได้- เช่น หากระบบไม่รองรับภาพเคลื่อนไหวบางรายการ คุณอาจแสดงภาพนิ่งแทนได้
คำอธิบายประกอบ @RequiresSchemaVersion
- คําอธิบายประกอบ
@RequiresSchemaVersion
ในเมธอด ProtoLayout จะระบุเวอร์ชันสคีมาของโปรแกรมแสดงผลขั้นต่ำที่จําเป็นสําหรับให้เมธอดนั้นทํางานตามที่อธิบายไว้ (ตัวอย่าง)- แม้ว่าการเรียกใช้เมธอดที่ต้องใช้โปรแกรมแสดงผลเวอร์ชันสูงกว่าที่พร้อมใช้งานในอุปกรณ์จะไม่ทำให้แอปขัดข้อง แต่อาจส่งผลให้เนื้อหาไม่แสดงหรือระบบละเว้นฟีเจอร์
ตัวอย่าง
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 จะมาจาก Play Store หรือการอัปเดตระบบ ไม่สามารถบังคับให้ติดตั้งโปรแกรมแสดงผลเวอร์ชันที่เฉพาะเจาะจงได้)
ฟีเจอร์แสดงตัวอย่างการ์ดของ Android Studio ใช้โปรแกรมแสดงผลที่ฝังอยู่ในไลบรารี Jetpack ProtoLayout ที่โค้ดของคุณใช้อยู่ อีกวิธีหนึ่งคือใช้ไลบรารี Jetpack เวอร์ชันอื่นเมื่อทดสอบการ์ด
ย้ายข้อมูลไปยังการ์ด 1.5 / ProtoLayout 1.3 (Material 3 Expressive)
อัปเดตไลบรารี Tile ของ Jetpack เพื่อใช้ประโยชน์จากการปรับปรุงล่าสุด ซึ่งรวมถึงการเปลี่ยนแปลง UI เพื่อให้ Tile ผสานรวมกับระบบได้อย่างราบรื่น
Jetpack Tiles 1.5 และ Jetpack ProtoLayout 1.3 มีการปรับปรุงและการเปลี่ยนแปลงที่น่าสนใจหลายประการ ซึ่งรวมถึงฟีเจอร์ต่อไปนี้
- API คล้ายกับ Compose สำหรับอธิบาย UI
- คอมโพเนนต์ Material 3 Expressive ซึ่งรวมถึงปุ่มที่แนบไปกับขอบด้านล่างและการรองรับภาพที่ได้รับการปรับปรุง เช่น ภาพเคลื่อนไหว Lottie, ประเภทไล่ระดับสีเพิ่มเติม และรูปแบบเส้นโค้งใหม่ - หมายเหตุ: คุณใช้ฟีเจอร์บางอย่างเหล่านี้ได้โดยไม่ต้องย้ายข้อมูลไปยัง API ใหม่
คำแนะนำ
- ย้ายข้อมูลการ์ดทั้งหมดพร้อมกัน หลีกเลี่ยงการผสมผสานเวอร์ชันการ์ดภายในแอป แม้ว่าคอมโพเนนต์ Material 3 จะอยู่ในอาร์ติแฟกต์แยกต่างหาก (
androidx.wear.protolayout:protolayout-material3
) ซึ่งทำให้ในทางเทคนิคแล้วสามารถใช้ทั้งการ์ด M2.5 และ M3 ในแอปเดียวกันได้ แต่เราขอแนะนำอย่างยิ่งว่าอย่าใช้แนวทางนี้ เว้นแต่ว่าจำเป็นจริงๆ (เช่น หากแอปมีการ์ดจํานวนมากซึ่งย้ายข้อมูลพร้อมกันไม่ได้) - ใช้หลักเกณฑ์ UX ของการ์ด เนื่องจากการ์ดมีโครงสร้างและเทมเพลตที่ตายตัว คุณจึงควรใช้การออกแบบในตัวอย่างที่มีอยู่เป็นจุดเริ่มต้นสำหรับการออกแบบของคุณเอง
- ทดสอบกับหน้าจอและแบบอักษรขนาดต่างๆ ไทล์มักจะมีข้อมูลจำนวนมาก ทำให้ข้อความ (โดยเฉพาะเมื่อวางบนปุ่ม) เสี่ยงที่จะแสดงเกินขอบและถูกตัด หากต้องการลดปัญหานี้ ให้ใช้คอมโพเนนต์ที่สร้างไว้ล่วงหน้าและหลีกเลี่ยงการปรับแต่งอย่างละเอียด ทดสอบโดยใช้ฟีเจอร์แสดงตัวอย่างการ์ดของ Android Studio รวมถึงในอุปกรณ์จริงหลายเครื่อง
กระบวนการย้ายข้อมูล
อัปเดตทรัพยากร Dependency
ก่อนอื่น ให้อัปเดตไฟล์ build.gradle.kts
อัปเดตเวอร์ชันและเปลี่ยน Dependency ของ 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 ส่วนใหญ่จะยังคงเหมือนเดิม
การเปลี่ยนแปลงหลักในการย้ายข้อมูลนี้ส่งผลต่อคอมโพเนนต์ UI ดังนั้น การติดตั้งใช้งาน TileService
รวมถึงกลไกการโหลดทรัพยากรต่างๆ ของคุณจึงควรต้องมีการแก้ไขเพียงเล็กน้อยหรือไม่ต้องแก้ไขเลย
ข้อยกเว้นหลักเกี่ยวข้องกับการติดตามกิจกรรมของการ์ด หากแอปใช้ onTileEnterEvent()
หรือ onTileLeaveEvent()
คุณควรย้ายข้อมูลไปยัง onRecentInteractionEventsAsync()
ตั้งแต่ API 36 เป็นต้นไป ระบบจะจัดกลุ่มเหตุการณ์เหล่านี้
ปรับโค้ดการสร้างเลย์เอาต์
ใน ProtoLayout 1.2 (M2.5) เมธอด onTileRequest()
จะแสดงผลเป็น TileBuilders.Tile
ออบเจ็กต์นี้มีองค์ประกอบต่างๆ ซึ่งรวมถึง TimelineBuilders.Timeline
ที่มี LayoutElement
ที่อธิบาย UI ของการ์ด
เมื่อใช้ 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) })
}
ความแตกต่างที่สำคัญมีดังนี้
- การยกเลิกการสร้าง รูปแบบตัวสร้างแบบดั้งเดิมสําหรับคอมโพเนนต์ UI ของ Material3 จะถูกแทนที่ด้วยไวยากรณ์ที่สื่อความหมายมากขึ้นซึ่งได้รับแรงบันดาลใจจาก Compose (คอมโพเนนต์ที่ไม่ใช่ UI เช่น String/Color/Modifiers ก็มี wrapper ใหม่ใน Kotlin ด้วย)
- ฟังก์ชันการจัดเรียงและเริ่มต้นมาตรฐาน เลย์เอาต์ M3 ต้องใช้ฟังก์ชันการจัดโครงสร้างและฟังก์ชันเริ่มต้นมาตรฐาน ได้แก่
materialScope()
และprimaryLayout()
ฟังก์ชันที่จําเป็นเหล่านี้จะเริ่มต้นสภาพแวดล้อม M3 (ธีม, ขอบเขตคอมโพเนนต์ผ่านmaterialScope
) และกำหนดเลย์เอาต์ตามช่องหลัก (ผ่านprimaryLayout
) โดยต้องเรียกใช้ทั้ง 2 ฟังก์ชัน 1 ครั้งต่อเลย์เอาต์
ธีม
สี
ฟีเจอร์เด่นของ Material 3 Expressive คือ "ธีมแบบไดนามิก" ซึ่งการ์ดที่เปิดใช้ฟีเจอร์นี้ (เปิดอยู่โดยค่าเริ่มต้น) จะแสดงในธีมที่ระบบมีให้ (ความพร้อมใช้งานขึ้นอยู่กับอุปกรณ์และการกำหนดค่าของผู้ใช้)
การเปลี่ยนแปลงอีกอย่างหนึ่งใน M3 คือการเพิ่มจํานวนโทเค็นสีจาก 4 เป็น 29 โทนสีใหม่จะอยู่ในคลาส ColorScheme
การจัดวางตัวอักษร
M3 อาศัยค่าคงที่ขนาดแบบอักษรที่กําหนดไว้ล่วงหน้าเป็นอย่างมาก ซึ่งคล้ายกับ M2.5 เราไม่แนะนําให้ระบุขนาดแบบอักษรโดยตรง ค่าคงที่เหล่านี้อยู่ในคลาส Typography
และมีตัวเลือกที่หลากหลายมากขึ้น
ดูรายละเอียดทั้งหมดได้ในเอกสารประกอบเกี่ยวกับการพิมพ์
รูปทรง
คอมโพเนนต์ M3 ส่วนใหญ่จะแตกต่างกันไปตามมิติข้อมูลของรูปร่างและสี
textButton
(ใน mainSlot
) ที่มีรูปร่าง full

textButton เดียวกันที่มีรูปร่าง small

คอมโพเนนต์
คอมโพเนนต์ M3 มีความยืดหยุ่นและกำหนดค่าได้มากกว่าคอมโพเนนต์ M2.5 อย่างเห็นได้ชัด ขณะที่ M2.5 มักต้องใช้คอมโพเนนต์ที่แตกต่างกันสำหรับการจัดการภาพอย่างหลากหลาย M3 มักใช้คอมโพเนนต์ "ฐาน" ทั่วไปที่กําหนดค่าได้สูงซึ่งมีค่าเริ่มต้นที่ดี
หลักการนี้ใช้กับเลย์เอาต์ "รูท" ใน M2.5 จะเป็น PrimaryLayout
หรือ EdgeContentLayout
ใน M3 หลังจากสร้าง MaterialScope
ระดับบนสุดรายการเดียวแล้ว ระบบจะเรียกใช้ฟังก์ชัน primaryLayout()
ซึ่งจะแสดงเลย์เอาต์รูทโดยตรง (ไม่ต้องใช้บิลเดอร์) และรับ LayoutElements
สำหรับ "ช่อง" หลายช่อง เช่น titleSlot
, mainSlot
และ bottomSlot
ช่องเหล่านี้สามารถป้อนข้อมูลด้วยคอมโพเนนต์ UI ที่เฉพาะเจาะจง เช่น ข้อมูลที่แสดงผลโดย text(), button() หรือ card() หรือโครงสร้างเลย์เอาต์ เช่น Row
หรือ Column
จาก LayoutElementBuilders
ธีมเป็นการเพิ่มประสิทธิภาพที่สำคัญอีกอย่างหนึ่งของ M3 โดยค่าเริ่มต้น องค์ประกอบ UI จะเป็นไปตามข้อกำหนดเฉพาะด้านการจัดรูปแบบ M3 โดยอัตโนมัติและรองรับธีมแบบไดนามิก
M2.5 | M3 |
---|---|
องค์ประกอบอินเทอร์แอกทีฟ | |
Button หรือ Chip |
|
ข้อความ | |
Text |
text() |
สัญญาณบอกสถานะความคืบหน้า | |
CircularProgressIndicator |
circularProgressIndicator() หรือ segmentedCircularProgressIndicator() |
เลย์เอาต์ | |
PrimaryLayout หรือ EdgeContentLayout |
primaryLayout() |
— | buttonGroup() |
รูปภาพ | |
— | icon() , avatarImage() หรือ backgroundImage() |
ตัวปรับแต่ง
ใน M3 Modifiers
ซึ่งคุณใช้ตกแต่งหรือเพิ่มคอมโพเนนต์จะคล้ายกับ Compose มากขึ้น การเปลี่ยนแปลงนี้ช่วยลดการเขียนโค้ดซ้ำได้โดยการสร้างประเภทภายในที่เหมาะสมโดยอัตโนมัติ (การเปลี่ยนแปลงนี้ไม่เกี่ยวข้องกับการใช้คอมโพเนนต์ UI ของ M3 หากจำเป็น คุณสามารถใช้ตัวแก้ไขสไตล์โปรแกรมสร้างจาก ProtoLayout 1.2 กับคอมโพเนนต์ UI ของ 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 จะอนุญาตให้แสดงคอมโพเนนต์ UI หลายรายการโดยใช้ API ที่ได้รับแรงบันดาลใจจาก Compose แต่องค์ประกอบเลย์เอาต์พื้นฐาน เช่น แถวและคอลัมน์จาก LayoutElementBuilders
จะยังคงใช้รูปแบบตัวสร้างต่อไป หากต้องการลดช่องว่างด้านรูปแบบนี้และเพิ่มความสอดคล้องกับ 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 / ProtoLayout 1.0
ตั้งแต่เวอร์ชัน 1.2 เป็นต้นไป Tiles Layout API ส่วนใหญ่จะอยู่ในเนมสเปซ androidx.wear.protolayout
หากต้องการใช้ API เวอร์ชันล่าสุด ให้ทําตามขั้นตอนการย้ายข้อมูลต่อไปนี้ในโค้ด
อัปเดตทรัพยากร Dependency
ในไฟล์บิลด์ของโมดูลแอป ให้ทำการเปลี่ยนแปลงต่อไปนี้
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
ควรเหมือนเดิมเปลี่ยนชื่อเมธอดที่เลิกใช้งาน 2-3 เมธอดจากคลาส TileService และ TileBuilder
TileBuilders
:getTimeline()
ถึงgetTileTimeline()
และsetTimeline()
ถึงsetTileTimeline()
TileService
: จากonResourcesRequest()
เป็นonTileResourcesRequest()
RequestBuilders.TileRequest
:getDeviceParameters()
ถึงgetDeviceConfiguration()
,setDeviceParameters()
ถึงsetDeviceConfiguration()
,getState()
ถึงgetCurrentState()
และsetState()
ถึงsetCurrentState()