เริ่มต้นใช้งานการ์ด


หากต้องการเริ่มแสดงการ์ดจากแอป ให้รวมทรัพยากร Dependency ต่อไปนี้ไว้ในไฟล์ build.gradle ของแอป

Groovy

dependencies {
    // Use to implement support for wear tiles
    implementation "androidx.wear.tiles:tiles:1.6.2"

    // Use to utilize standard components and layouts in your tiles
    implementation "androidx.wear.protolayout:protolayout:1.4.2"

    // Use to utilize components and layouts with Material Design in your tiles
    implementation "androidx.wear.protolayout:protolayout-material:1.4.2"

    // Use to include dynamic expressions in your tiles
    implementation "androidx.wear.protolayout:protolayout-expression:1.4.2"

    // Use to preview wear tiles in your own app
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.6.2"

    // Use to fetch tiles from a tile provider in your tests
    testImplementation "androidx.wear.tiles:tiles-testing:1.6.2"
}

Kotlin

dependencies {
    // Use to implement support for wear tiles
    implementation("androidx.wear.tiles:tiles:1.6.2")

    // Use to utilize standard components and layouts in your tiles
    implementation("androidx.wear.protolayout:protolayout:1.4.2")

    // Use to utilize components and layouts with Material Design in your tiles
    implementation("androidx.wear.protolayout:protolayout-material:1.4.2")

    // Use to include dynamic expressions in your tiles
    implementation("androidx.wear.protolayout:protolayout-expression:1.4.2")

    // Use to preview wear tiles in your own app
    debugImplementation("androidx.wear.tiles:tiles-renderer:1.6.2")

    // Use to fetch tiles from a tile provider in your tests
    testImplementation("androidx.wear.tiles:tiles-testing:1.6.2")
}

แนวคิดสำคัญ

การ์ดไม่ได้สร้างขึ้นในลักษณะเดียวกับแอป Android และใช้แนวคิดที่แตกต่างกัน ดังนี้

  • เทมเพลตเลย์เอาต์: กำหนดการจัดเรียงองค์ประกอบภาพโดยรวมบนจอแสดงผล ซึ่งทำได้โดยใช้ฟังก์ชัน primaryLayout()
  • องค์ประกอบเลย์เอาต์: แสดงองค์ประกอบกราฟิกแต่ละรายการ เช่น ปุ่มหรือการ์ด หรือองค์ประกอบหลายรายการที่จัดกลุ่มเข้าด้วยกันโดยใช้คอลัมน์ buttonGroup หรือที่คล้ายกัน ซึ่งฝังอยู่ภายในเทมเพลตเลย์เอาต์
  • ทรัพยากร: ออบเจ็กต์ ResourceBuilders.Resources ประกอบด้วยแผนที่ของคู่คีย์-ค่าของทรัพยากร Android (รูปภาพ) ที่จำเป็นสำหรับการแสดงผลเลย์เอาต์ และเวอร์ชัน
  • ไทม์ไลน์: ออบเจ็กต์ TimelineBuilders.Timeline คือรายการอินสแตนซ์ของออบเจ็กต์เลย์เอาต์อย่างน้อย 1 รายการ คุณสามารถระบุกลไกและนิพจน์ต่างๆ เพื่อระบุว่าเมื่อใดที่โปรแกรมแสดงผลควรเปลี่ยนจากออบเจ็กต์เลย์เอาต์หนึ่งไปยังอีกออบเจ็กต์หนึ่ง เช่น เพื่อหยุดแสดงเลย์เอาต์ในเวลาที่เจาะจง
  • State: โครงสร้างข้อมูลประเภท StateBuilders.State ที่ส่งระหว่างการ์ดและแอป เพื่อให้คอมโพเนนต์ทั้ง 2 รายการสื่อสารกันได้ เช่น หากมีการแตะปุ่มบนการ์ด สถานะจะเก็บรหัสของปุ่มไว้ นอกจากนี้ คุณยังแลกเปลี่ยนประเภทข้อมูลโดยใช้แผนที่ได้ด้วย
  • ไทล์: ออบเจ็กต์ TileBuilders.Tile ที่แสดงถึงไทล์ ซึ่งประกอบด้วยไทม์ไลน์ รหัสเวอร์ชันของทรัพยากร ช่วงเวลาความใหม่ และสถานะ
  • Protolayout: คำนี้ปรากฏในชื่อของคลาสต่างๆ ที่เกี่ยวข้องกับไทล์ และหมายถึงไลบรารี Wear OS Protolayout ซึ่งเป็นไลบรารีกราฟิกที่ใช้ในแพลตฟอร์ม Wear OS ต่างๆ

สร้างการ์ด

ใช้ Material3TileService (แนะนำ)

เมื่อสร้างการ์ด Material 3 (androidx.wear.tiles:tiles:1.6.0 ขึ้นไป) ให้ขยาย Material3TileService แทนคลาส TileService ระดับต่ำกว่าเสมอ Material3TileService มีสถาปัตยกรรมที่เน้น Kotlin เป็นหลักซึ่งช่วยให้การพัฒนาการ์ดง่ายขึ้น ดังนี้

  • โคโรทีน Kotlin ในตัว: ใช้ฟังก์ชัน MaterialScope.tileResponse(requestParams: TileRequest): Tile แบบระงับเดียวแทนการใช้ ListenableFuture และลบล้าง onTileRequest()
  • กำหนดค่าไว้ล่วงหน้า MaterialScope: tileResponse() ทำงานโดยมี MaterialScope เป็นตัวรับ (กำหนดค่าผ่านพารามิเตอร์คอนสตรัคเตอร์ เช่น allowDynamicTheme และ defaultColorScheme) คุณจึงไม่จำเป็นต้องรวมเลย์เอาต์ไว้ในการเรียก materialScope() ที่ซ้ำซ้อน
  • การลงทะเบียนทรัพยากรแบบเรียกใช้ครั้งเดียว: มี ProtoLayoutScope เพื่อลงทะเบียนทรัพยากรรูปภาพในบรรทัดโดยอัตโนมัติ และแสดงผลทั้งเลย์เอาต์การ์ดและทรัพยากรในการเรียกใช้ Binder ของระบบครั้งเดียว เนื่องจาก Material3TileService จัดการทรัพยากรโดยอัตโนมัติ (finalonTileResourcesRequest()) โปรดอย่าลบล้าง onTileResourcesRequest()
class MyTileService : Material3TileService() {

    override suspend fun MaterialScope.tileResponse(requestParams: TileRequest): Tile =
        tile(
            timeline =
            Timeline.fromLayoutElement(
                primaryLayout(
                    mainSlot = {
                        text("Hello, World!".layoutString, typography = BODY_LARGE)
                    }
                )
            )
        )
}

สถาปัตยกรรม TileService พื้นฐาน

Material3TileService สร้างขึ้นจากคลาส TileService พื้นฐาน ซึ่งตัวอย่างที่เหลือในคู่มือนี้ใช้เพื่อแสดงแนวคิดระดับต่ำ

หากต้องการแสดงการ์ดจากแอป ให้ใช้บริการประเภท TileService และลงทะเบียนในไฟล์ Manifest จากนั้น ระบบจะขอไทล์ที่จำเป็นระหว่างการเรียกใช้ onTileRequest() และขอทรัพยากรระหว่างการเรียกใช้ onTileResourcesRequest()

class MyTileService : TileService() {

    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(
            Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setTileTimeline(
                    Timeline.fromLayoutElement(
                        materialScope(this, requestParams.deviceConfiguration) {
                            primaryLayout(
                                mainSlot = {
                                    text("Hello, World!".layoutString, typography = BODY_LARGE)
                                }
                            )
                        }
                    )
                )
                .build()
        )

    override fun onTileResourcesRequest(requestParams: ResourcesRequest) =
        Futures.immediateFuture(Resources.Builder().setVersion(RESOURCES_VERSION).build())
}

จากนั้นเพิ่มบริการภายในแท็ก <application> ของไฟล์ AndroidManifest.xml

<service
    android:name=".snippets.m3.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 จะลงทะเบียนบริการนี้เป็นผู้ให้บริการการ์ด

ไอคอน ป้ายกำกับ คำอธิบาย และทรัพยากรตัวอย่างจะแสดงต่อผู้ใช้เมื่อกำหนดค่าการ์ดในโทรศัพท์หรือนาฬิกา โปรดทราบว่าทรัพยากรตัวอย่างรองรับตัวระบุทรัพยากรมาตรฐานทั้งหมดของ Android จึงสามารถปรับเปลี่ยนตัวอย่างตามปัจจัยต่างๆ เช่น ขนาดหน้าจอและภาษาของอุปกรณ์ได้ ดูคำแนะนำเพิ่มเติมได้ที่รายการตรวจสอบตัวอย่าง

ทำให้แอปใช้งานได้ และเพิ่มการ์ดลงในภาพสไลด์ของการ์ด (มีวิธีแสดงตัวอย่างการ์ดที่เหมาะกับนักพัฒนาแอปมากกว่าด้วย แต่ตอนนี้ให้ทำด้วยตนเองไปก่อน)

การ์ด Wear OS ที่สร้างด้วย Material 3 ซึ่งแสดงข้อความ &quot;Hello World&quot;
รูปที่ 1 "Hello World"

ดูตัวอย่างที่เสร็จสมบูรณ์ได้ที่ตัวอย่างโค้ดใน GitHub หรือ Codelab

สร้าง UI สำหรับการ์ด

องค์ประกอบ UI ของ Material 3 Expressive สร้างขึ้นโดยใช้วิธีการที่มีโครงสร้างซึ่งขับเคลื่อนโดยรูปแบบเครื่องมือสร้างที่ปลอดภัยในการกำหนดประเภทของ Kotlin

การจัดวาง

ดูคำแนะนำเกี่ยวกับหลักการออกแบบที่อยู่เบื้องหลังการสร้างเลย์เอาต์การ์ดที่มีประสิทธิภาพและปรับเปลี่ยนตามพื้นที่โฆษณาได้ที่เลย์เอาต์ทั่วไปสำหรับการ์ด

หากต้องการสร้างเลย์เอาต์ ให้ทำดังนี้

  1. เริ่มต้นขอบเขต Material Design: เรียกใช้ฟังก์ชัน materialScope() โดยระบุ context และ deviceConfiguration ที่จำเป็น คุณสามารถรวมพารามิเตอร์ที่ไม่บังคับ เช่น allowDynamicTheme และ defaultColorScheme allowDynamicTheme จะเป็น true โดยค่าเริ่มต้น และ defaultColorScheme จะแสดง ColorScheme ที่ใช้เมื่อสีแบบไดนามิกไม่พร้อมใช้งาน เช่น เมื่อผู้ใช้ปิดฟีเจอร์นี้ หรือเมื่ออุปกรณ์ไม่รองรับ หรือ allowDynamicTheme เป็น false) เมื่อใช้ API ของ ImageResource เช่น backgroundImage() ใน TileService ที่กำหนดเอง ให้เรียกใช้ materialScopeWithResources() แทน

  2. สร้าง UI ภายในขอบเขต: ต้องกำหนดคอมโพเนนต์ UI ทั้งหมดสำหรับเลย์เอาต์การ์ดหนึ่งๆ ภายใน Lambda ของการเรียก materialScope() ระดับบนสุดรายการเดียว ฟังก์ชันคอมโพเนนต์เหล่านี้ เช่น primaryLayout() และ textEdgeButton() เป็นฟังก์ชันส่วนขยายใน MaterialScope และจะใช้ได้เมื่อเรียกใช้ในขอบเขต Receiver นี้เท่านั้น

    materialScope(
        context = context,
        deviceConfiguration =
        requestParams.deviceConfiguration, // requestParams is passed to onTileRequest
        defaultColorScheme = myFallbackColorScheme
    ) {
        // inside the MaterialScope, you can call functions like primaryLayout()
        primaryLayout(
            titleSlot = { text(text = "Title".layoutString) },
            mainSlot = { text(text = "Main Content".layoutString) },
            bottomSlot = {
                textEdgeButton(
                    labelContent = { text("Action".layoutString) },
                    onClick = clickable()
                )
            }
        )
    }

สล็อต

ใน M3 เลย์เอาต์การ์ดจะใช้แนวทางที่ได้รับแรงบันดาลใจจาก Compose ซึ่งใช้ช่องที่แตกต่างกัน 3 ช่อง โดยเรียงจากบนลงล่างดังนี้

  1. titleSlot โดยปกติจะใช้สำหรับชื่อหรือส่วนหัวหลัก
  2. mainSlot สำหรับเนื้อหาหลัก
  3. bottomSlot ซึ่งมักใช้สำหรับการดำเนินการหรือข้อมูลเสริม และปุ่มขอบจะปรากฏที่นี่ด้วย
เลย์เอาต์การ์ดที่แสดง titleSlot, mainSlot และ bottomSlot
รูปที่ 2 titleSlot, mainSlot และ bottomSlot

เนื้อหาของแต่ละช่องมีดังนี้

  • titleSlot (ไม่บังคับ): โดยปกติแล้วจะเป็นคำไม่กี่คำที่สร้างโดย text()
  • mainSlot (บังคับ): คอมโพเนนต์ที่จัดระเบียบเป็นโครงสร้าง เช่น แถว คอลัมน์ และกลุ่มปุ่ม นอกจากนี้ยังฝังคอมโพเนนต์เหล่านี้ซ้อนกันได้ เช่น คอลัมน์สามารถมีแถวได้
  • bottomSlot (ไม่บังคับ): โดยปกติแล้วจะใส่ปุ่มที่ชิดขอบหรือป้ายกำกับข้อความ

เนื่องจากไทล์เลื่อนไม่ได้ จึงไม่มีคอมโพเนนต์สำหรับการแบ่งหน้า การเลื่อน หรือการจัดการรายการเนื้อหาที่ยาว ตรวจสอบว่าเนื้อหายังคงมองเห็นได้เมื่อขนาดแบบอักษรเพิ่มขึ้นหรือข้อความยาวขึ้นเนื่องจากการแปล

คอมโพเนนต์ UI

ไลบรารี protolayout-material3 มีคอมโพเนนต์จำนวนมากที่ออกแบบตามข้อกำหนดเฉพาะของ Material 3 Expressive และคำแนะนำเกี่ยวกับอินเทอร์เฟซผู้ใช้

ปุ่ม

ปุ่มจะเน้นการดำเนินการเป็นหลัก โดยจะทำหน้าที่ทริกเกอร์การดำเนินการที่เฉพาะเจาะจง เนื้อหาของปุ่มแต่ละปุ่ม เช่น ไอคอนหรือข้อความสั้นๆ จะระบุการดำเนินการ

  • textButton(): ปุ่มที่มีช่องเดียวสำหรับเนื้อหาข้อความ (สั้น)
  • iconButton(): ปุ่มที่มีช่องเดียวเพื่อแสดงไอคอน
  • avatarButton(): ปุ่มอวาตาร์รูปทรงแคปซูลที่มีช่องสูงสุด 3 ช่องสำหรับใส่เนื้อหาที่แสดงป้ายกำกับและป้ายกำกับรองที่ซ้อนกันในแนวตั้ง และรูปภาพ (อวาตาร์) ข้างๆ
  • imageButton(): ปุ่มรูปภาพที่คลิกได้ซึ่งไม่มีช่องเพิ่มเติม มีเพียงรูปภาพ (เช่น backgroundImage เป็นพื้นหลัง)
  • compactButton(): ปุ่มขนาดกะทัดรัดที่มีช่องให้เลือกสูงสุด 2 ช่องเพื่อใช้เนื้อหาที่ซ้อนกันในแนวนอนซึ่งแสดงไอคอนและข้อความข้างๆ
  • button(): ปุ่มรูปทรงแคปซูลที่มีช่องให้ใส่เนื้อหาได้สูงสุด 3 ช่อง ซึ่งแสดงป้ายกำกับและป้ายกำกับรองที่ซ้อนกันในแนวตั้ง และไอคอนข้างๆ

ปุ่ม Edge

ปุ่มขอบเป็นปุ่มเฉพาะแบบเต็มความกว้างที่ยึดไว้ที่ด้านล่างของหน้าจอกลมของนาฬิกา ซึ่งแสดงถึงการดำเนินการที่สำคัญที่สุดที่ต้องทำจากหน้าจอการ์ดปัจจุบัน

  • iconEdgeButton(): ปุ่มขอบที่มีช่องเดียวสำหรับใส่ไอคอนหรือเนื้อหาขนาดเล็กทรงกลมที่คล้ายกัน
  • textEdgeButton(): ปุ่มขอบที่มีช่องเดียวสำหรับใส่ข้อความหรือเนื้อหาที่มีความยาวและความกว้างใกล้เคียงกัน

การ์ด

การ์ดจะเน้นข้อมูลเป็นหลัก ซึ่งจะแสดงคอลเล็กชันของข้อมูลที่มีโครงสร้างและเกี่ยวข้องกัน แม้ว่าคุณจะสร้างการ์ดแบบอินเทอร์แอกทีฟได้ แต่โดยปกติแล้วการ์ดจะแสดงข้อมูลสรุป ซึ่งผู้ใช้สามารถแตะเพื่อดูรายละเอียดเพิ่มเติมหรือดำเนินการที่เกี่ยวข้องได้

  • titleCard(): การ์ดไตเติ้ลที่มีช่อง 1-3 ช่อง ซึ่งมักจะเป็นข้อความ
  • appCard(): การ์ดแอปที่มีช่องสูงสุด 5 ช่อง โดยปกติจะเป็นแบบข้อความ
  • textDataCard(): การ์ดข้อมูลที่มีช่องซ้อนกันในแนวตั้งสูงสุด 3 ช่อง โดยปกติจะเป็นข้อความหรือตัวเลข
  • iconDataCard(): การ์ดข้อมูลที่มีช่องซ้อนกันในแนวตั้งสูงสุด 3 ช่อง โดยปกติจะเป็นข้อความหรือตัวเลข พร้อมไอคอน
  • graphicDataCard(): การ์ดข้อมูลกราฟิกที่มีช่องสำหรับข้อมูลกราฟิก เช่น ตัวบอกความคืบหน้า และช่องที่ซ้อนกันในแนวตั้งสูงสุด 2 ช่อง ซึ่งมักใช้สำหรับคำอธิบายข้อความ

ตัวบอกสถานะความคืบหน้า

  • circularProgressIndicator(): ระบุความคืบหน้าสู่เป้าหมายโดยใช้องค์ประกอบแบบรัศมี
  • segmentedCircularProgressIndicator(): แสดงความคืบหน้าในการบรรลุเป้าหมายโดยใช้องค์ประกอบแบบรัศมีที่มีระยะต่างๆ ที่ชัดเจน

จัดกลุ่มองค์ประกอบเลย์เอาต์

  • buttonGroup(): เลย์เอาต์คอมโพเนนต์ที่วางองค์ประกอบย่อยในลำดับแนวนอน
  • primaryLayout(): เลย์เอาต์แบบเต็มหน้าจอที่แสดงถึงสไตล์เลย์เอาต์ M3 ที่แนะนำซึ่งปรับเปลี่ยนตามอุปกรณ์และดูแลการจัดวางองค์ประกอบ พร้อมกับระยะขอบและระยะห่างจากขอบที่แนะนำ

ใช้ธีม

ใน Material 3 Expressive ระบบสีจะกำหนดโดยบทบาทสีมาตรฐาน 29 บทบาท ซึ่งจัดเป็น 6 กลุ่ม ได้แก่ สีปฐมภูมิ สีทุติยภูมิ สีตติยภูมิ สีข้อผิดพลาด สีพื้นผิว และสีเส้นขอบ

ระบบสี Material 3 Expressive ซึ่งแสดงบทบาทของสีที่จัดระเบียบเป็นกลุ่มต่างๆ เช่น สีปฐมภูมิ สีทุติยภูมิ สีตติยภูมิ สีข้อผิดพลาด สีพื้นผิว และสีเส้นขอบ
รูปที่ 3 ระบบสี Material 3 Expressive

ColorScheme จะจับคู่บทบาททั้ง 29 บทบาทนี้กับสีที่สอดคล้องกัน และเนื่องจากเป็นส่วนหนึ่งของ MaterialScope และต้องสร้างคอมโพเนนต์ภายในนั้น คอมโพเนนต์จึงใช้สีจากรูปแบบโดยอัตโนมัติ วิธีนี้ช่วยให้องค์ประกอบ UI ทั้งหมดเป็นไปตามมาตรฐาน Material Design โดยอัตโนมัติ

หากต้องการให้ผู้ใช้เลือกระหว่างรูปแบบสีที่คุณกำหนด เช่น รูปแบบสีที่แสดงถึงสีของแบรนด์ และรูปแบบสีที่ระบบมีให้ ซึ่งได้มาจากหน้าปัดปัจจุบันของผู้ใช้หรือรูปแบบสีที่ผู้ใช้เลือก ให้เริ่มต้น MaterialScope ดังนี้

val myColorScheme =
    ColorScheme(
        primary = Color.rgb(0, 0, 255).argb, // Blue
        onPrimary = Color.rgb(255, 255, 255).argb, // White
        // 27 more
    )

materialScope(
    context = context,
    deviceConfiguration = requestParams.deviceConfiguration,
    defaultColorScheme = myColorScheme
) {
    // If the user selects "no theme" in settings, myColorScheme is used.
    // Otherwise, the system-provided theme is used.
}

หากเลือกตัวเลือกนี้ ให้ระบุไอคอนการ์ดขาวดำเพื่อให้สามารถปรับสีได้อย่างถูกต้องเพื่อการมองเห็นที่ดีที่สุดในทุกธีม

หากต้องการบังคับให้การ์ดปรากฏในรูปแบบสีที่คุณระบุ ให้ปิดใช้การรองรับการกำหนดธีมแบบไดนามิกโดยตั้งค่า allowDynamicTheme เป็น false ดังนี้

materialScope(
    context = context,
    deviceConfiguration = requestParams.deviceConfiguration,
    allowDynamicTheme = false,
    defaultColorScheme = myColorScheme
) {
    // myColorScheme is *always* used.
}

สี

แต่ละคอมโพเนนต์จะใช้ชุดย่อยของบทบาทสี 29 บทบาทที่กำหนดโดย ColorScheme ตัวอย่างเช่น ปุ่มใช้สีได้สูงสุด 4 สี ซึ่งโดยค่าเริ่มต้นจะนำมาจากกลุ่ม "หลัก" ของColorSchemeที่ใช้งานอยู่ ดังนี้

โทเค็นคอมโพเนนต์ ButtonColors บทบาท ColorScheme
containerColor หลัก
iconColor onPrimary
labelColor onPrimary
secondaryLabelColor onPrimary (ความทึบแสง 0.8)

ดูคำแนะนำโดยละเอียดเกี่ยวกับการใช้สีกับการออกแบบ Wear OS ได้ที่คู่มือการออกแบบสี

คุณอาจต้องเบี่ยงเบนจากโทเค็นสีเริ่มต้นสำหรับองค์ประกอบ UI ที่เฉพาะเจาะจง เช่น คุณอาจต้องการให้ textEdgeButton หนึ่งใช้สีจากกลุ่ม "รอง" หรือ "ตติยภูมิ" แทน "หลัก" เพื่อให้โดดเด่นและมีคอนทราสต์ที่ดีขึ้น

คุณปรับแต่งสีของคอมโพเนนต์ได้หลายวิธี ดังนี้

  1. ใช้ฟังก์ชันตัวช่วยสำหรับสีที่กำหนดไว้ล่วงหน้า ใช้ฟังก์ชันตัวช่วย เช่น filledTonalButtonColors() เพื่อใช้รูปแบบปุ่มมาตรฐานสำหรับ Material 3 Expressive ฟังก์ชันเหล่านี้จะสร้างอินสแตนซ์ ButtonColors ที่กำหนดค่าไว้ล่วงหน้าซึ่งแมปสไตล์ทั่วไป เช่น แบบทึบ แบบโทนสี หรือแบบเส้นขอบ กับบทบาทที่เหมาะสมจาก ColorScheme ที่ใช้งานอยู่ภายใน MaterialScope ซึ่งจะช่วยให้คุณใช้สไตล์ที่สอดคล้องกันได้โดยไม่ต้องกำหนดสีแต่ละสีสำหรับประเภทปุ่มทั่วไปด้วยตนเอง

    textEdgeButton(
        colors = filledButtonColors(), // default
        /* OR colors = filledTonalButtonColors() */
        /* OR colors = filledVariantButtonColors() */
        // ... other parameters
    )

    สำหรับบัตร ให้ใช้ฟังก์ชัน filledCardColors() ที่เทียบเท่า

    นอกจากนี้ คุณยังแก้ไขออบเจ็กต์ ButtonColors ที่ฟังก์ชันตัวช่วยแสดงผลได้โดยใช้เมธอด copy() หากต้องการเปลี่ยนโทเค็นเพียง 1 หรือ 2 รายการเท่านั้น

    textEdgeButton(
        colors =
        filledButtonColors()
            .copy(
                containerColor = colorScheme.tertiary,
                labelColor = colorScheme.onTertiary
            ),
        // ... other parameters
    )

  2. ระบุบทบาทสีทดแทนอย่างชัดเจน สร้างออบเจ็กต์ ButtonColors ของคุณเอง แล้วส่งไปยังคอมโพเนนต์ สำหรับบัตร ให้ใช้ออบเจ็กต์ CardColors ที่เทียบเท่า

    textEdgeButton(
        colors =
        ButtonColors(
            // the materialScope makes colorScheme available
            containerColor = colorScheme.secondary,
            iconColor = colorScheme.secondaryDim,
            labelColor = colorScheme.onSecondary,
            secondaryLabelColor = colorScheme.onSecondary
        ),
        // ... other parameters
    )

  3. ระบุสีคงที่ (ใช้ด้วยความระมัดระวัง) แม้ว่าโดยทั่วไปเราจะแนะนำให้ระบุสีตามบทบาทเชิงความหมาย (เช่น colorScheme.primary) แต่คุณก็ระบุค่าสีโดยตรงได้เช่นกัน ควรใช้วิธีนี้เท่าที่จำเป็น เนื่องจากอาจทำให้ไม่สอดคล้องกับธีมโดยรวม โดยเฉพาะอย่างยิ่งหากธีมมีการเปลี่ยนแปลงแบบไดนามิก

    textEdgeButton(
        colors = filledButtonColors().copy(
            containerColor = android.graphics.Color.RED.argb, // Using named colors
            labelColor = 0xFFFFFF00.toInt().argb // Using a hex code for yellow
        ),
        // ... other parameters
    )

การพิมพ์

ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ตัวพิมพ์อย่างมีประสิทธิภาพในการออกแบบได้ที่คู่มือการออกแบบตัวพิมพ์

ข้อความทั้งหมดในการ์ดจะแสดงผลโดยใช้แบบอักษรที่ระบบมีให้ เพื่อสร้างความสอดคล้องกันของภาพในแพลตฟอร์ม Wear OS และเพื่อเพิ่มประสิทธิภาพ กล่าวคือ หน้าต่างไม่รองรับแบบตัวพิมพ์ที่กำหนดเอง ใน Wear OS 6 ขึ้นไป แบบอักษรนี้จะเป็นแบบอักษรเฉพาะของ OEM ในกรณีส่วนใหญ่จะเป็นแบบอักษรแบบแปรผัน ซึ่งจะมอบประสบการณ์ที่สื่ออารมณ์ได้มากขึ้นและการควบคุมที่ละเอียดยิ่งขึ้น

โดยปกติแล้ว หากต้องการสร้างรูปแบบข้อความ คุณจะต้องใช้เมธอด text() ร่วมกับค่าคงที่ของการพิมพ์ คอมโพเนนต์นี้ช่วยให้คุณใช้บทบาทการจัดพิมพ์ที่กำหนดไว้ล่วงหน้าใน Material 3 Expressive ได้ ซึ่งจะช่วยให้การ์ดเป็นไปตามแนวทางปฏิบัติแนะนำด้านการจัดพิมพ์ที่กำหนดไว้เพื่อให้อ่านง่ายและมีลำดับชั้น ไลบรารีมีชุดค่าคงที่ของการจัดพิมพ์เชิงความหมาย 18 ค่า เช่น BODY_MEDIUM ค่าคงที่เหล่านี้ยังส่งผลต่อแกนแบบอักษรนอกเหนือจากขนาดด้วย

text(
    text = "Hello, World!".layoutString,
    typography = BODY_MEDIUM,
)

หากต้องการควบคุมเพิ่มเติม คุณสามารถระบุการตั้งค่าเพิ่มเติมได้ ใน Wear OS 6 ขึ้นไป มีแนวโน้มที่จะใช้แบบอักษรที่ปรับเปลี่ยนได้ ซึ่งคุณสามารถแก้ไขตามแกนตัวเอียง น้ำหนัก ความกว้าง และความกลม คุณควบคุมแกนเหล่านี้ได้โดยใช้พารามิเตอร์ settings ดังนี้

text(
    text = "Hello, World".layoutString,
    italic = true,

    // Use elements defined in androidx.wear.protolayout.LayoutElementBuilders.FontSetting
    settings =
    listOf(
        weight(500),
        width(100F),
        roundness(100)
    ),
)

สุดท้าย หากต้องการควบคุมขนาดหรือระยะห่างระหว่างตัวอักษร (ไม่แนะนำ) ให้ใช้ basicText() แทน text() และสร้างค่าสำหรับพร็อพเพอร์ตี้ fontStyle โดยใช้ fontStyle())

รูปร่างและระยะขอบ

คุณเปลี่ยนรัศมีมุมของคอมโพเนนต์เกือบทุกรายการได้โดยใช้พร็อพเพอร์ตี้ shape ค่ามาจากพร็อพเพอร์ตี้ MaterialScope shapes:

textButton(
    height = expand(),
    width = expand(),
    shape = shapes.medium, // OR another value like shapes.full
    colors = filledVariantButtonColors(),
    labelContent = { text("Hello, World!".layoutString) },
)

หลังจากเปลี่ยนรูปร่างของคอมโพเนนต์แล้ว หากคิดว่ามีพื้นที่ว่างรอบขอบจอแสดงผลมากหรือน้อยเกินไป ให้ปรับระยะขอบโดยใช้พารามิเตอร์ margin ของ primaryLayout() ดังนี้

primaryLayout(
    mainSlot = {
        textButton(
            shape = shapes.small,
            /* ... */
        )
    },
    // margin constants defined in androidx.wear.protolayout.material3.PrimaryLayoutMargins
    margins = MAX_PRIMARY_LAYOUT_MARGIN,
)

เส้นโค้ง

ระบบรองรับคอนเทนเนอร์ย่อย Arc ต่อไปนี้

  • ArcLine: แสดงผลเส้นโค้งรอบส่วนโค้ง
  • ArcText: แสดงผลข้อความโค้งในส่วนโค้ง
  • ArcAdapter: แสดงผลองค์ประกอบเลย์เอาต์พื้นฐานในส่วนโค้ง โดยวาดที่เส้นสัมผัสของส่วนโค้ง

ดูข้อมูลเพิ่มเติมได้ที่เอกสารอ้างอิงสำหรับองค์ประกอบแต่ละประเภท

คีย์ตัวปรับแต่ง

องค์ประกอบเลย์เอาต์ที่ใช้ได้ทุกรายการสามารถใช้ตัวแก้ไขได้ (ไม่บังคับ) ใช้ตัวแก้ไขเหล่านี้เพื่อวัตถุประสงค์ต่อไปนี้

  • เปลี่ยนลักษณะที่ปรากฏของเลย์เอาต์ เช่น เพิ่มพื้นหลัง เส้นขอบ หรือระยะห่างจากขอบให้กับองค์ประกอบเลย์เอาต์
  • เพิ่มข้อมูลเมตาเกี่ยวกับเลย์เอาต์ เช่น เพิ่มตัวแก้ไขความหมายลงในองค์ประกอบเลย์เอาต์เพื่อใช้กับโปรแกรมอ่านหน้าจอ
  • เพิ่มฟังก์ชันการทำงาน เช่น เพิ่มตัวแก้ไขที่คลิกได้ลงในองค์ประกอบเลย์เอาต์เพื่อทำให้การ์ดเป็นแบบอินเทอร์แอกทีฟ ดูข้อมูลเพิ่มเติมได้ที่โต้ตอบกับการ์ด

ตัวอย่างเช่น เราสามารถปรับแต่งรูปลักษณ์และข้อมูลเมตาเริ่มต้นของ Image ได้ ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้

private fun myImage(): LayoutElement =
    Image.Builder()
        .setWidth(dp(24f))
        .setHeight(dp(24f))
        .setResourceId("image_id")
        .setModifiers(
            Modifiers.Builder()
                .setBackground(Background.Builder().setColor(argb(0xFFFF0000.toInt())).build())
                .setPadding(ModifiersBuilders.Padding.Builder().setStart(dp(12f)).build())
                .setSemantics(Semantics.Builder().setContentDescription("Image description").build())
                .build()
        )
        .build()

Spannable

Spannable เป็นคอนเทนเนอร์ประเภทพิเศษที่จัดวางองค์ประกอบคล้ายกับข้อความ ซึ่งจะมีประโยชน์เมื่อคุณต้องการใช้รูปแบบที่แตกต่างกันกับสตริงย่อยเพียงรายการเดียวในบล็อกข้อความขนาดใหญ่ ซึ่งเป็นสิ่งที่ไม่สามารถทำได้ด้วยองค์ประกอบ Text

คอนเทนเนอร์ Spannable มีรายการย่อย Span รายการ ไม่อนุญาตให้มีองค์ประกอบย่อยอื่นๆ หรืออินสแตนซ์ Spannable ที่ซ้อนกัน

บุตรหลานใน Span มี 2 ประเภท ได้แก่

  • SpanText: แสดงผลข้อความด้วยรูปแบบที่เฉพาะเจาะจง
  • SpanImage: แสดงผลรูปภาพในบรรทัดเดียวกับข้อความ

เช่น คุณสามารถทำให้คำว่า "world" ในไทล์ "Hello world" เป็นตัวเอียงและแทรกรูปภาพระหว่างคำได้ ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้

private fun mySpannable(): LayoutElement =
    LayoutElementBuilders.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()

ใช้งานกับทรัพยากร

ไทล์ไม่มีสิทธิ์เข้าถึงทรัพยากรของแอป ซึ่งหมายความว่าคุณไม่สามารถส่งรหัสรูปภาพ Android ไปยังองค์ประกอบเลย์เอาต์ Image และคาดหวังให้ระบบแก้ไขได้ แต่ให้ลบล้างเมธอด onTileResourcesRequest() และระบุทรัพยากรด้วยตนเองแทน

คุณระบุรูปภาพภายในเมธอด onTileResourcesRequest() ได้ 2 วิธีดังนี้

  • ระบุทรัพยากรที่ถอนออกได้โดยใช้ setAndroidResourceByResId()
  • ระบุรูปภาพแบบไดนามิกเป็น ByteArray โดยใช้ setInlineResource()

override fun onTileResourcesRequest(
    requestParams: ResourcesRequest
) = Futures.immediateFuture(
    Resources.Builder()
        .setVersion("1")
        .addIdToImageMapping(
            "image_from_resource",
            ResourceBuilders.ImageResource.Builder()
                .setAndroidResourceByResId(
                    ResourceBuilders.AndroidImageResourceByResId.Builder()
                        .setResourceId(R.drawable.ic_walk)
                        .build()
                ).build()
        )
        .addIdToImageMapping(
            "image_inline",
            ResourceBuilders.ImageResource.Builder()
                .setInlineResource(
                    ResourceBuilders.InlineImageResource.Builder()
                        .setData(imageAsByteArray)
                        .setWidthPx(48)
                        .setHeightPx(48)
                        .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
                        .build()
                ).build()
        ).build()
)

รายการตรวจสอบรูปภาพตัวอย่างการ์ด

ระบบจะแสดงรูปภาพตัวอย่างการ์ดที่อ้างอิงในไฟล์ Manifest ของแอป Android ในเครื่องมือแก้ไขภาพสไลด์ของการ์ดเพื่อเพิ่มการ์ดใหม่ เครื่องมือแก้ไขนี้จะปรากฏทั้งในอุปกรณ์ Wear OS และในแอปที่ใช้ร่วมกันของนาฬิกาในโทรศัพท์

โปรดตรวจสอบรายละเอียดต่อไปนี้เกี่ยวกับหน้าต่างของคุณเพื่อช่วยให้ผู้ใช้ได้รับประโยชน์สูงสุดจากรูปภาพตัวอย่างนี้

  • แสดงการออกแบบล่าสุด ตัวอย่างควรแสดงการออกแบบล่าสุดของไทล์อย่างถูกต้อง
  • ใช้มิติข้อมูลที่แนะนำ รูปภาพตัวอย่างควรมีขนาด 400 x 400 พิกเซลเพื่อให้ได้คุณภาพการแสดงผลที่ดีที่สุดและมอบประสบการณ์การใช้งานที่ดีแก่ผู้ใช้
  • ใช้ธีมสีแบบคงที่ ใช้ธีมสีแบบคงที่ของการ์ด ไม่ใช่แบบไดนามิก
  • มีไอคอนแอป ตรวจสอบว่าไอคอนของแอปปรากฏที่ด้านบนของรูปภาพตัวอย่าง
  • แสดงสถานะโหลด/เข้าสู่ระบบ ตัวอย่างควรแสดงสถานะ "โหลดแล้ว" หรือ "เข้าสู่ระบบแล้ว" ที่ทำงานได้อย่างสมบูรณ์ โดยหลีกเลี่ยงเนื้อหาที่ว่างเปล่าหรือเนื้อหาตัวยึดตำแหน่ง
  • ใช้ประโยชน์จากกฎการแก้ไขทรัพยากรเพื่อการปรับแต่ง (ไม่บังคับ) ลองใช้กฎการแก้ไขทรัพยากรของ Android เพื่อแสดงตัวอย่างที่ตรงกับการตั้งค่าขนาดการแสดงผล ภาษา หรือภาษาของอุปกรณ์ ซึ่งจะเป็นประโยชน์อย่างยิ่งหากลักษณะที่ปรากฏของไทล์แตกต่างกันไปในแต่ละอุปกรณ์