หากต้องการเริ่มให้บริการการ์ดจากแอป ให้รวมไลบรารีต่อไปนี้ไว้ในไฟล์ 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
คือรายการอินสแตนซ์ของออบเจ็กต์เลย์เอาต์อย่างน้อย 1 รายการ คุณสามารถระบุกลไกและนิพจน์ต่างๆ เพื่อระบุว่าเมื่อใดที่โปรแกรมแสดงผลควรเปลี่ยนจากออบเจ็กต์เลย์เอาต์หนึ่งไปยังอีกออบเจ็กต์หนึ่ง เช่น เพื่อหยุดแสดงเลย์เอาต์ในเวลาที่เจาะจง - สถานะ: โครงสร้างข้อมูลประเภท
StateBuilders.State
ที่ส่งผ่านระหว่างการ์ดกับแอปเพื่อให้คอมโพเนนต์ทั้ง 2 รายการสื่อสารกันได้ เช่น หากมีการแตะปุ่มบนการ์ด สถานะจะเก็บรหัสของปุ่มนั้นไว้ นอกจากนี้ คุณยังแลกเปลี่ยนประเภทข้อมูลโดยใช้แผนที่ได้ด้วย - การ์ด: ออบเจ็กต์
TileBuilders.Tile
ที่แสดงการ์ด ซึ่งประกอบด้วยไทม์ไลน์ รหัสเวอร์ชันทรัพยากร ช่วงเวลาความใหม่ และสถานะ - Protolayout: คํานี้ปรากฏในชื่อของคลาสต่างๆ ที่เกี่ยวข้องกับการ์ด และหมายถึงไลบรารี Protolayout ของ Wear OS ซึ่งเป็นไลบรารีกราฟิกที่ใช้ในแพลตฟอร์มต่างๆ ของ Wear OS
สร้างการ์ด
หากต้องการระบุการ์ดจากแอป ให้ติดตั้งใช้งานบริการประเภท TileService
และลงทะเบียนบริการในไฟล์ Manifest จากข้อมูลนี้ ระบบจะขอการ์ดที่จําเป็นระหว่างการเรียกใช้ 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>
ตัวกรองสิทธิ์และ Intent จะลงทะเบียนบริการนี้ในฐานะผู้ให้บริการไทล์
ไอคอน ป้ายกำกับ คำอธิบาย และทรัพยากรตัวอย่างจะแสดงต่อผู้ใช้เมื่อผู้ใช้กำหนดค่าการ์ดในโทรศัพท์หรือนาฬิกา
ดูตัวอย่างที่สมบูรณ์ได้ที่ตัวอย่างโค้ดใน GitHub หรือ Codelab
ภาพรวมวงจรชีวิตของบริการแผนที่ย่อย
เมื่อสร้างและประกาศ TileService
ในไฟล์ Manifest ของแอปแล้ว คุณจะตอบสนองต่อการเปลี่ยนแปลงสถานะของบริการการ์ดได้
TileService
เป็นบริการที่มีผลผูกพัน TileService
จะได้รับการเชื่อมโยงเนื่องจากคำขอแอปของคุณ หรือในกรณีที่ระบบต้องสื่อสารกับ TileService
วงจรชีวิตของบริการที่เชื่อมโยงโดยทั่วไปจะมีเมธอดการเรียกกลับ 4 รายการ ได้แก่ onCreate()
, onBind()
, onUnbind()
และ onDestroy()
ระบบจะเรียกใช้เมธอดเหล่านี้ทุกครั้งที่บริการเข้าสู่ระยะวงจรใหม่
นอกจากการเรียกกลับที่ควบคุมวงจรบริการที่เชื่อมโยงแล้ว คุณยังใช้เมธอดอื่นๆ สำหรับวงจร TileService
โดยเฉพาะได้ด้วย บริการการ์ดทั้งหมดต้องใช้ onTileRequest()
และ onTileResourcesRequest()
เพื่อตอบสนองคำขออัปเดตจากระบบ
onTileAddEvent()
: ระบบจะเรียกใช้เมธอดนี้เฉพาะเมื่อผู้ใช้เพิ่มการ์ดของคุณเป็นครั้งแรก และในกรณีที่ผู้ใช้นำการ์ดออกและเพิ่มการ์ดอีกครั้ง นี่เป็นเวลาที่เหมาะที่สุดในการเริ่มต้นใช้งานแบบครั้งเดียวonTileAddEvent()
จะเรียกใช้เฉพาะเมื่อมีการกำหนดค่าชุดการ์ดใหม่เท่านั้น ไม่ใช่ทุกครั้งที่ระบบสร้างการ์ด ตัวอย่างเช่น เมื่อรีบูตหรือเปิดอุปกรณ์onTileAddEvent()
จะไม่เรียกใช้สำหรับการ์ดที่เพิ่มไว้แล้ว คุณใช้getActiveTilesAsync()
แทนได้เพื่อดูภาพรวมของการ์ดที่เป็นของคุณซึ่งใช้งานอยู่onTileRemoveEvent()
: ระบบจะเรียกใช้เมธอดนี้เฉพาะในกรณีที่ผู้ใช้นำการ์ดของคุณออกเท่านั้นonTileEnterEvent()
: ระบบจะเรียกใช้เมธอดนี้เมื่อการ์ดที่ผู้ให้บริการรายนี้ระบุปรากฏขึ้นบนหน้าจอonTileLeaveEvent()
: ระบบจะเรียกใช้เมธอดนี้เมื่อการ์ดที่ผู้ให้บริการรายนี้ระบุไม่อยู่ในมุมมองบนหน้าจอonTileRequest()
: ระบบจะเรียกใช้เมธอดนี้เมื่อระบบขอไทม์ไลน์ใหม่จากผู้ให้บริการรายนี้onTileResourcesRequest()
: ระบบจะเรียกใช้เมธอดนี้เมื่อระบบขอแพ็กเกจทรัพยากรจากผู้ให้บริการรายนี้ กรณีนี้อาจเกิดขึ้นเมื่อโหลดไทล์เป็นครั้งแรกหรือเมื่อใดก็ตามที่เวอร์ชันทรัพยากรมีการเปลี่ยนแปลง
ค้นหาว่าการ์ดใดที่ใช้งานอยู่
การ์ดที่ใช้งานอยู่คือการ์ดที่เพิ่มไว้เพื่อแสดงบนนาฬิกา ใช้เมธอดแบบคงที่ getActiveTilesAsync()
ของ TileService
เพื่อค้นหาว่าการ์ดใดของแอปคุณที่ใช้งานอยู่
สร้าง UI สำหรับการ์ด
เลย์เอาต์ของการ์ดเขียนโดยใช้รูปแบบ Builder เลย์เอาต์ของการ์ดจะสร้างขึ้นเหมือนต้นไม้ที่ประกอบด้วยคอนเทนเนอร์เลย์เอาต์และองค์ประกอบเลย์เอาต์พื้นฐาน องค์ประกอบเลย์เอาต์แต่ละรายการมีพร็อพเพอร์ตี้ ซึ่งคุณตั้งค่าได้ผ่านเมธอด setter ต่างๆ
องค์ประกอบเลย์เอาต์พื้นฐาน
ระบบรองรับองค์ประกอบภาพต่อไปนี้จากไลบรารี protolayout
ควบคู่ไปกับคอมโพเนนต์ Material
Text
: แสดงผลสตริงข้อความโดยตัดขึ้นบรรทัดใหม่หรือไม่ก็ได้Image
: แสดงผลรูปภาพSpacer
: เพิ่มระยะห่างจากขอบระหว่างองค์ประกอบหรือทำหน้าที่เป็นตัวแบ่งเมื่อคุณตั้งค่าสีพื้นหลัง
คอมโพเนนต์ของ Material
นอกจากองค์ประกอบพื้นฐานแล้ว ไลบรารี protolayout-material
ยังมีคอมโพเนนต์ที่ช่วยให้การออกแบบการ์ดสอดคล้องกับคําแนะนําของอินเทอร์เฟซผู้ใช้ Material Design
Button
: คอมโพเนนต์วงกลมที่คลิกได้ซึ่งออกแบบมาเพื่อใส่ไอคอนChip
: คอมโพเนนต์รูปทรงสนามกีฬาที่คลิกได้ซึ่งออกแบบมาเพื่อใส่ข้อความได้สูงสุด 2 บรรทัดและมีไอคอน (ไม่บังคับ)CompactChip
: คอมโพเนนต์รูปทรงสนามกีฬาที่คลิกได้ซึ่งออกแบบมาเพื่อบรรจุบรรทัดข้อความTitleChip
: คอมโพเนนต์รูปทรงสนามกีฬาที่คลิกได้ ซึ่งคล้ายกับChip
แต่มีความสูงมากกว่าเพื่อให้รองรับข้อความชื่อCircularProgressIndicator
: สัญญาณบอกสถานะความคืบหน้าแบบวงกลมที่สามารถวางไว้ภายในEdgeContentLayout
เพื่อแสดงความคืบหน้ารอบขอบของหน้าจอ
คอนเทนเนอร์เลย์เอาต์
ระบบรองรับคอนเทนเนอร์ต่อไปนี้พร้อมกับเลย์เอาต์ Material
Row
: จัดวางองค์ประกอบย่อยตามแนวนอนทีละรายการColumn
: จัดวางองค์ประกอบย่อยในแนวตั้งทีละรายการBox
: วางซ้อนองค์ประกอบย่อยไว้บนกันArc
: จัดวางองค์ประกอบย่อยเป็นวงกลมSpannable
: ใช้FontStyles
ที่เฉพาะเจาะจงกับส่วนของข้อความ พร้อมกับการสลับข้อความและรูปภาพ ดูข้อมูลเพิ่มเติมได้ที่Spannables
คอนเทนเนอร์ทุกรายการมีคอนเทนเนอร์ย่อยได้อย่างน้อย 1 รายการ ซึ่งคอนเทนเนอร์ย่อยเองก็เป็นคอนเทนเนอร์ได้เช่นกัน เช่น Column
อาจมีองค์ประกอบ Row
หลายรายการเป็นองค์ประกอบย่อย ซึ่งจะทำให้เกิดเลย์เอาต์แบบตารางกริด
ตัวอย่างเช่น ไทล์ที่มีเลย์เอาต์คอนเทนเนอร์และองค์ประกอบเลย์เอาต์ย่อย 2 รายการอาจมีลักษณะดังนี้
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(); }
เลย์เอาต์ของวัสดุ
นอกจากเลย์เอาต์พื้นฐานแล้ว คลัง protolayout-material
ยังมีเลย์เอาต์ที่เน้นการแสดงผลตามแนวคิดบางอย่างซึ่งออกแบบมาเพื่อรองรับองค์ประกอบใน "ช่อง" ที่เฉพาะเจาะจง
PrimaryLayout
: วางการดําเนินการหลักCompactChip
รายการเดียวที่ด้านล่างโดยให้เนื้อหาอยู่ตรงกลางด้านบนMultiSlotLayout
: จัดวางป้ายกำกับหลักและรองโดยมีเนื้อหาที่ไม่บังคับคั่นอยู่ตรงกลางและCompactChip
ที่ไม่บังคับที่ด้านล่างMultiButtonLayout
: จัดตำแหน่งชุดปุ่มที่จัดเรียงตามหลักเกณฑ์ของ MaterialEdgeContentLayout
: จัดตำแหน่งเนื้อหาไว้รอบๆ ขอบหน้าจอ เช่นCircularProgressIndicator
เมื่อใช้เลย์เอาต์นี้ เนื้อหาภายในจะมีระยะขอบและระยะห่างจากขอบที่เหมาะสมโดยอัตโนมัติ
ส่วนโค้ง
ระบบรองรับArc
คอนเทนเนอร์ย่อยต่อไปนี้
ArcLine
: แสดงผลเส้นโค้งรอบๆ ส่วนโค้งArcText
: แสดงผลข้อความโค้งในอาร์ค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
คือคอนเทนเนอร์ประเภทพิเศษที่จัดวางองค์ประกอบคล้ายกับข้อความ ซึ่งมีประโยชน์เมื่อคุณต้องการใช้รูปแบบอื่นกับสตริงย่อยเพียงรายการเดียวในบล็อกข้อความขนาดใหญ่ ซึ่งคุณทำไม่ได้หากใช้องค์ประกอบ Text
คอนเทนเนอร์ Spannable
เต็มไปด้วยรายการย่อย Span
ไม่อนุญาตให้มีองค์ประกอบย่อยอื่นๆ หรืออินสแตนซ์ Spannable
ที่ฝังอยู่
Span
ย่อยมี 2 ประเภทดังนี้
เช่น คุณอาจทำให้ "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()
ทำได้ 2 วิธีดังนี้
- ระบุทรัพยากรที่วาดได้โดยใช้
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
ในเขียน- สร้างการ์ดการตั้งค่าด่วนที่กำหนดเองสำหรับแอป