ดูตัวอย่าง UI ใน Compose สำหรับ Wear OS

ตัวอย่าง Compose ใน Android Studio ช่วยให้คุณตรวจสอบและยืนยัน Composable ของ Wear OS ในขนาดจอแสดงผลของนาฬิกา ขอบกลม และการปรับขนาดแบบอักษร ต่างๆ ได้โดยตรงใน IDE โดยไม่ต้องติดตั้งใช้งานแอปในนาฬิกาจริงหรือ โปรแกรมจำลอง

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


ตั้งค่าการอ้างอิงของเวอร์ชันตัวอย่าง

หากต้องการใช้คำอธิบายประกอบตัวอย่าง Wear OS Compose และคำจำกัดความของอุปกรณ์ ให้เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในไฟล์ build.gradle.kts ของโมดูล

dependencies {
    // Provides @WearPreview* multipreview annotations
    // (such as @WearPreviewDevices and @WearPreviewFontScales)
    implementation("androidx.wear.compose:compose-ui-tooling:1.7.0")

    // Provides WearDevices constants
    // (such as WearDevices.SMALL_ROUND and WearDevices.LARGE_ROUND)
    implementation("androidx.wear:wear-tooling-preview:1.0.0")

    // Standard Compose preview support and interactive/animation inspection
    implementation("androidx.compose.ui:ui-tooling-preview")
    debugImplementation("androidx.compose.ui:ui-tooling")
}

เลือกสิ่งที่ต้องการแสดงตัวอย่าง: หน้าจอเทียบกับคอมโพเนนต์

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

ดูตัวอย่างแบบเต็มหน้าจอ (AppScaffold + ScreenScaffold)

เมื่อดูตัวอย่างทั้งหน้าจอ ให้ห่อหุ้ม Composable ของหน้าจอในทั้ง AppScaffold และ ScreenScaffold เสมอโดยใช้คำอธิบายประกอบตัวอย่างอุปกรณ์ Wear ซึ่งจะ แสดงผลนาฬิกาทรงกลมและช่วยให้มั่นใจได้ว่า

  • TimeText จะแสดงที่ขอบโค้งด้านบนของหน้าปัด
  • ScrollIndicator จะปรากฏตามขอบด้านขวา
  • EdgeButton อยู่ในตำแหน่งที่เหมาะสมและตัดที่เส้นโค้งด้านล่าง
  • ระยะห่างจากขอบเนื้อหาและการตัดหน้าจอแบบวงกลมแสดงถึงฮาร์ดแวร์ของนาฬิกาจริงได้อย่างถูกต้อง
@WearPreviewDevices
@Composable
fun WorkoutScreenPreview() {
    MaterialTheme {
        // AppScaffold provides the top-level TimeText overlay
        AppScaffold {
            // WorkoutScreen contains its own ScreenScaffold and content
            WorkoutScreen(
                heartRate = 142,
                elapsedTime = "12:45"
            )
        }
    }
}
WorkoutScreenPreview แสดงผลใน WearDevices.SMALL_ROUND

กลมเล็ก (192x192dp)

WorkoutScreenPreview แสดงผลใน WearDevices.LARGE_ROUND

กลมใหญ่ (227x227dp)

แสดงตัวอย่างคอมโพเนนต์ที่แยก

เมื่อแสดงตัวอย่างคอมโพเนนต์แต่ละรายการ เช่น Card, Button หรือชิปสถานะที่กำหนดเอง ให้ละเว้นพารามิเตอร์ device และใช้ @Preview มาตรฐานที่มีพื้นหลังสีเข้ม ซึ่งจะช่วยให้สีและความคมชัดของ Wear Material 3 ปรากฏอย่างถูกต้องโดยไม่ต้องแสดงหน้าปัดนาฬิกาทรงกลมแบบเต็ม

@Preview(
    showBackground = true,
    backgroundColor = 0xFF000000
)
@Composable
fun HeartRateCardPreview() {
    MaterialTheme {
        HeartRateCard(bpm = 142, zone = "Aerobic")
    }
}
ตัวอย่างคอมโพเนนต์ HeartRateCardPreview แบบแยกโดยไม่มีกรอบนาฬิกา

การแสดงตัวอย่างคอมโพเนนต์แบบแยก (ไม่มีกรอบอุปกรณ์)


คำอธิบายประกอบแบบหลายตัวอย่างในตัว

androidx.wear.compose.ui.tooling.preview แพ็กเกจมีคำอธิบายประกอบในตัว ซึ่งกำหนดค่าพื้นหลังสีเข้มโดยอัตโนมัติ (backgroundColor = 0xFF000000, showBackground = true) และขนาดอุปกรณ์นาฬิกาทรงกลม:

หมายเหตุ สิ่งที่แสดง กรณีที่ควรใช้
@WearPreviewSmallRound 1 ตัวอย่างบน WearDevices.SMALL_ROUND (192x192dp) การทำซ้ำอย่างรวดเร็วในขนาดการแสดงผลแบบวงกลมที่มีข้อจำกัดมากที่สุด
@WearPreviewLargeRound ตัวอย่าง 1 รายการใน WearDevices.LARGE_ROUND (227x227dp) การตรวจสอบความหนาแน่นของเลย์เอาต์และการเว้นวรรคเพิ่มเติมในนาฬิกาขนาดใหญ่
@WearPreviewDevices ตัวอย่าง 2 รายการ: SMALL_ROUND และ LARGE_ROUND การตรวจสอบแบบหลายอุปกรณ์มาตรฐานสำหรับ Composable ทุกหน้าจอ
@WearPreviewFontScales ตัวอย่าง 6 รายการใน SMALL_ROUND ในทุกขนาดแบบอักษรของ Wear ได้แก่ เล็ก (0.94f), ปกติ (1.0f), กลาง (1.06f), ใหญ่ (1.12f), ใหญ่มาก (1.18f) และใหญ่ที่สุด (1.24f) ตรวจสอบการตัดข้อความ การใช้เครื่องหมายจุดไข่ปลา และการขยายความสูงของปุ่ม

คุณสามารถซ้อน @WearPreviewDevices และ @WearPreviewFontScales ในฟังก์ชันแสดงตัวอย่างเดียวกันเพื่อสร้างเมทริกซ์ทดสอบที่ครอบคลุมได้โดยทำดังนี้

@WearPreviewDevices
@WearPreviewFontScales
@Composable
fun MessageDetailScreenPreview() {
    MaterialTheme {
        AppScaffold {
            MessageDetailScreen(
                sender = "Alex",
                body = "Running 5 mins late!"
            )
        }
    }
}

คำอธิบายประกอบตัวอย่างที่กำหนดเองและสเปคฮาร์ดแวร์

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

ค่าคงที่ WearDevices และข้อมูลจำเพาะของฮาร์ดแวร์ที่กำหนดเองที่พร้อมใช้งาน

ออบเจ็กต์ androidx.wear.tooling.preview.devices.WearDevices มี รหัสอุปกรณ์มาตรฐานดังนี้

  • WearDevices.SMALL_ROUND ("id:wearos_small_round", 192x192dp)
  • WearDevices.LARGE_ROUND ("id:wearos_large_round", 227x227dp)

หากต้องการแสดงตัวอย่างบนจอแสดงผลทรงกลมขนาดใหญ่พิเศษ (เช่น นาฬิกาขนาด 44 มม.-45 มม. หรือรุ่น Ultra ที่ 240x240dp) ให้ส่งspec:สตริงที่กำหนดเองไปยังพารามิเตอร์ device

@Preview(
    name = "XL Round Watch (240dp)",
    device = "spec:width=240dp,height=240dp,dpi=320,isRound=true",
    showBackground = true,
    backgroundColor = 0xFF000000
)
@Composable
fun WorkoutScreenXlPreview() {
    MaterialTheme {
        AppScaffold {
            WorkoutScreen(heartRate = 142, elapsedTime = "12:45")
        }
    }
}

สร้างคำอธิบายประกอบแบบหลายตัวอย่างที่กำหนดเอง

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

@Preview(
    name = "1. Standard Large Round",
    group = "Layout extremes",
    device = WearDevices.LARGE_ROUND,
    backgroundColor = 0xFF000000,
    showBackground = true
)
@Preview(
    name = "2. Extreme Small Round (Largest Font + German)",
    group = "Layout extremes",
    device = WearDevices.SMALL_ROUND,
    fontScale = 1.24f,
    locale = "de-rDE",
    backgroundColor = 0xFF000000,
    showBackground = true
)
annotation class WearPreviewExtremes
ตัวอย่างโฆษณารูปกลมขนาดใหญ่มาตรฐาน

1. Standard Large Round

กลมเล็กมากที่มีการปรับขนาดแบบอักษรใหญ่ที่สุด

2. กลมเล็กมาก (แบบอักษรใหญ่ที่สุด + เยอรมัน)


ดูตัวอย่างคอลัมน์ที่เลื่อนได้ (TransformingLazyColumn)

โดยค่าเริ่มต้น TransformingLazyColumn จะเริ่มต้นด้วยรายการแรก (index = 0) ที่ปักหมุดไว้ที่ด้านบนของหน้าจอ อย่างไรก็ตาม ใน Wear OS รายการต่างๆ จะ เปลี่ยนความสูงและมุมโค้ง (SurfaceTransformation) เมื่อ เข้าใกล้ขอบโค้งด้านบนและด้านล่างของหน้าจอ และ EdgeButton จะปรากฏเมื่อเลื่อนไปที่ด้านล่างเท่านั้น

วิธีดูตัวอย่างลักษณะของรายการเมื่อเลื่อนลงมาครึ่งทางหรือที่ด้านล่างของรายการ

ขั้นตอนที่ 1: ยก TransformingLazyColumnState ใน Composable ของหน้าจอ

อนุญาตให้ Composable ของหน้าจอรับTransformingLazyColumnState พารามิเตอร์ที่มี rememberTransformingLazyColumnState() เป็นค่าเริ่มต้น

@Composable
fun InboxScreen(
    messages: List<Message>,
    columnState: TransformingLazyColumnState = rememberTransformingLazyColumnState(),
) {
    val transformationSpec = rememberTransformationSpec()

    ScreenScaffold(
        scrollState = columnState,
        edgeButton = {
            EdgeButton(onClick = { /* Compose new */ }) {
                Text("New message")
            }
        }
    ) { contentPadding ->
        TransformingLazyColumn(
            state = columnState,
            contentPadding = contentPadding,
        ) {
            items(messages.size) { index ->
                Card(
                    onClick = {},
                    modifier = Modifier
                        .fillMaxWidth()
                        .transformedHeight(this, transformationSpec)
                        .minimumVerticalContentPadding(
                            CardDefaults.minimumVerticalListContentPadding
                        ),
                    transformation = SurfaceTransformation(transformationSpec),
                ) {
                    Text(messages[index].subject)
                }
            }
        }
    }
}

ขั้นตอนที่ 2: ส่งinitialAnchorItemIndex@Preview

rememberTransformingLazyColumnStateยอมรับพารามิเตอร์การเลื่อนเริ่มต้นที่ไม่บังคับ 2 รายการ

  • initialAnchorItemIndex: Int: เมื่อตั้งค่าเป็นดัชนีที่ไม่ใช่ค่าลบ (เช่น 3) รายการจะเริ่มต้นด้วยรายการนั้นซึ่งอยู่ตรงกลาง วิวพอร์ตการดู
  • initialAnchorItemScrollOffset: Int: ออฟเซ็ตพิกเซลที่ไม่บังคับซึ่งใช้ เทียบกับรายการยึดที่กึ่งกลาง

คุณสามารถสร้างตัวอย่างแบบเทียบข้างเพื่อแสดงสถานะด้านบน ตรงกลาง (เลื่อน) และด้านล่าง (EdgeButton มองเห็นได้) ของหน้าจอเดียวกัน ได้โดยทำดังนี้

@WearPreviewLargeRound
@Composable
fun InboxScreenTopPreview() {
    MaterialTheme {
        AppScaffold {
            // Default (-1): Pinned to top of list (index 0)
            InboxScreen(messages = sampleMessages)
        }
    }
}

@WearPreviewLargeRound
@Composable
fun InboxScreenScrolledMiddlePreview() {
    MaterialTheme {
        AppScaffold {
            // Centers item index 3 in the viewport, showing top/bottom item morphing
            InboxScreen(
                messages = sampleMessages,
                columnState = rememberTransformingLazyColumnState(
                    initialAnchorItemIndex = 3
                )
            )
        }
    }
}

@WearPreviewLargeRound
@Composable
fun InboxScreenBottomEdgeButtonPreview() {
    MaterialTheme {
        AppScaffold {
            // Anchors on the last item so the EdgeButton is visible at the bottom
            InboxScreen(
                messages = sampleMessages,
                columnState = rememberTransformingLazyColumnState(
                    initialAnchorItemIndex = sampleMessages.lastIndex
                )
            )
        }
    }
}
ปักหมุด InboxScreen ไว้ที่ด้านบนของรายการ

ด้านบน (ค่าเริ่มต้น -1)

เลื่อนกล่องจดหมายไปยังดัชนีกลาง 3

กลาง (initialAnchorItemIndex = 3)

เลื่อนหน้าจอกล่องจดหมายไปด้านล่างโดยขยาย EdgeButton

ด้านล่าง (EdgeButton ขยาย)

เคล็ดลับ: คุณยังคลิกเริ่มโหมดอินเทอร์แอกทีฟใน @Preview ใน Android Studio เพื่อเลื่อน TransformingLazyColumn แบบเรียลไทม์ด้วยเมาส์หรือ แทร็กแพด และตรวจสอบSurfaceTransformation การมอร์ฟ EdgeButton ภาพเคลื่อนไหวตอนเข้า และScrollIndicator การเคลื่อนไหวแบบเรียลไทม์ได้ด้วย

การ์ด ScrollIndicator ระหว่างการจับภาพแบบเลื่อน (LocalScrollCaptureInProgress)

เมื่อเครื่องมือจับภาพการเลื่อนของระบบ (ภาพหน้าจอแบบยาว) หรือการทดสอบภาพหน้าจอแบบหลายเฟรม จะจับภาพการเลื่อน TransformingLazyColumn ให้สร้างชุด LocalScrollCaptureInProgress.current เป็น true ขณะจับภาพและต่อภาพ หลายๆ ช่องมองภาพในแนวตั้ง

เนื่องจาก ScreenScaffold ไม่ซ่อน scrollIndicator โดยอัตโนมัติในระหว่างการจับภาพการเลื่อน แถบเลื่อนแบบลอยจึงจะปรากฏซ้ำใน ทุกช่องที่ต่อกันของภาพหน้าจอยาว เว้นแต่คุณจะป้องกันอย่างชัดเจนด้วย !LocalScrollCaptureInProgress.current

ScreenScaffold(
    scrollState = columnState,
    scrollIndicator = {
        if (!LocalScrollCaptureInProgress.current) {
            ScrollIndicator(state = columnState)
        }
    }
) { contentPadding ->
    // TransformingLazyColumn content...
    // ...
}