ค้นหาข้อมูลสำหรับเลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่ด้วย mediaQuery

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

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

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

@Composable
fun VideoPlayer(
    // ...
) {
    // ...
            if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
                TabletopLayout()
            } else {
                FlatLayout()
            }
    // ...
}

เปิดใช้ฟังก์ชัน mediaQuery

หากต้องการเปิดใช้ฟังก์ชัน mediaQuery ให้ตั้งค่าแอตทริบิวต์ isMediaQueryIntegrationEnabled ของ ออบเจ็กต์ ComposeUiFlags เป็น true

class MyApplication : Application() {
    override fun onCreate() {
        ComposeUiFlags.isMediaQueryIntegrationEnabled = true
        super.onCreate()
    }
}

กำหนดเงื่อนไขด้วยพารามิเตอร์

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

พารามิเตอร์ ประเภทค่า คำอธิบาย
windowWidth Dp ความกว้างปัจจุบันของหน้าต่างในหน่วย dp
windowHeight Dp ความสูงปัจจุบันของหน้าต่างในหน่วย dp
windowPosture UiMediaScope.Posture ท่าทางปัจจุบันของหน้าต่างแอปพลิเคชัน
pointerPrecision UiMediaScope.PointerPrecision ความแม่นยำสูงสุดของอุปกรณ์ชี้ที่ใช้ได้
keyboardKind UiMediaScope.KeyboardKind ประเภทของแป้นพิมพ์ที่ใช้ได้หรือเชื่อมต่ออยู่
hasCamera Boolean อุปกรณ์รองรับกล้องหรือไม่
hasMicrophone Boolean อุปกรณ์รองรับไมโครโฟนหรือไม่
viewingDistance UiMediaScope.ViewingDistance ระยะห่างโดยทั่วไประหว่างผู้ใช้กับหน้าจออุปกรณ์

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

@Composable
fun VideoPlayer(
    // ...
) {
    // ...
            if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
                TabletopLayout()
            } else {
                FlatLayout()
            }
    // ...
}

ตัดสินใจตามขนาดหน้าต่าง

คลาสขนาดหน้าต่างคือชุดเบรกพอยต์ของวิวพอร์ตที่กำหนดไว้ล่วงหน้า ซึ่งช่วยคุณออกแบบ พัฒนา และทดสอบเลย์เอาต์แบบปรับเปลี่ยนได้ คุณสามารถเปรียบเทียบพารามิเตอร์ 2 รายการที่แสดงถึงขนาดหน้าต่างปัจจุบันกับเกณฑ์ที่กำหนดไว้ในคลาสขนาดหน้าต่าง ตัวอย่างต่อไปนี้จะเปลี่ยนจำนวนบานหน้าต่างตามความกว้างของหน้าต่าง WindowSizeClass คลาสมีค่าคงที่สำหรับเกณฑ์ ของคลาสขนาดหน้าต่าง (รูปที่ 1)

ฟังก์ชัน derivedMediaQuery จะประเมิน Lambda query และรวมผลลัพธ์ไว้ใน derivedStateOf เนื่องจาก windowWidth และ windowHeight อาจอัปเดตบ่อยครั้ง ให้เรียกใช้ฟังก์ชัน derivedMediaQuery แทนฟังก์ชัน mediaQuery เมื่ออ้างอิงพารามิเตอร์เหล่านั้นใน Lambda query

val narrowerThanMedium by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp
}
val narrowerThanExpanded by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp
}
when {
    narrowerThanMedium -> SinglePaneLayout()
    narrowerThanExpanded -> TwoPaneLayout()
    else -> ThreePaneLayout()
}

รูปที่ 1. ระบบจะอัปเดตเลย์เอาต์ตามความกว้างของหน้าต่าง

อัปเดตเลย์เอาต์ตามท่าทางของหน้าต่าง

พารามิเตอร์ windowPosture จะอธิบายท่าทางปัจจุบันของหน้าต่างเป็นออบเจ็กต์ UiMediaScope.Posture คุณสามารถตรวจสอบ ท่าทาง ปัจจุบันได้โดยการเปรียบเทียบพารามิเตอร์ กับค่าที่กำหนดไว้ในคลาส UiMediaScope.Posture ตัวอย่างต่อไปนี้จะเปลี่ยนเลย์เอาต์ตามท่าทางของหน้าต่าง

when {
    mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}

ตรวจสอบความแม่นยำของอุปกรณ์ชี้ที่ใช้ได้

อุปกรณ์ชี้ที่มีความแม่นยำสูงจะช่วยให้ผู้ใช้ชี้องค์ประกอบ UI ได้อย่างแม่นยำ ความแม่นยำของอุปกรณ์ชี้ขึ้นอยู่กับประเภทของอุปกรณ์

พารามิเตอร์ pointerPrecision จะอธิบายความแม่นยำของอุปกรณ์ชี้ที่ใช้ได้ เช่น เมาส์และหน้าจอสัมผัส คลาส UiMediaScope.PointerPrecision มีค่า 4 ค่า ได้แก่ Fine, Coarse, Blunt และ None None หมายความว่าไม่มีอุปกรณ์ชี้ที่ใช้ได้ ความแม่นยำจะเรียงจากสูงสุดไปต่ำสุดตามลำดับนี้ Fine, Coarse และ Blunt

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

ตัวอย่างต่อไปนี้แสดงปุ่มที่ใหญ่ขึ้นเมื่อผู้ใช้ใช้อุปกรณ์ชี้ที่มีความแม่นยำต่ำ

if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) {
    LargeSizeButton()
} else {
    NormalSizeButton()
}

ตรวจสอบประเภทแป้นพิมพ์ที่ใช้ได้

พารามิเตอร์ keyboardKind แสดงถึงประเภทของแป้นพิมพ์ที่ใช้ได้: Physical, Virtual และ None หากแป้นพิมพ์บนหน้าจอแสดงอยู่และมีแป้นพิมพ์ฮาร์ดแวร์ที่ใช้ได้ในเวลาเดียวกัน ระบบจะแก้พารามิเตอร์เป็น Physical หากตรวจไม่พบทั้ง 2 อย่าง ค่าของพารามิเตอร์จะเป็น None ตัวอย่างต่อไปนี้แสดงข้อความแนะนำให้ผู้ใช้เชื่อมต่อแป้นพิมพ์เมื่อตรวจไม่พบแป้นพิมพ์

if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) {
    SuggestKeyboardConnect()
}

ตรวจสอบว่าอุปกรณ์รองรับกล้องและไมโครโฟนหรือไม่

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

Row {
    OutlinedTextField(state = rememberTextFieldState())
    // Show the MicButton when the device supports a microphone.
    if (mediaQuery { hasMicrophone }) {
        MicButton()
    }
    // Show the CameraButton when the device supports a camera.
    if (mediaQuery { hasCamera }) {
        CameraButton()
    }
}

ปรับ UI ตามระยะห่างในการรับชมโดยประมาณ

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

คลาส UiMediaScope.ViewingDistance มีค่า 3 ค่า ได้แก่ Near, Medium และ Far Near หมายความว่าหน้าจออยู่ในระยะใกล้ และ Far หมายความว่ามีการดูอุปกรณ์จากระยะไกล ตัวอย่างต่อไปนี้จะเพิ่มขนาดแบบอักษรเมื่อระยะห่างในการรับชมเป็น Far หรือ Medium

val fontSize = when {
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp
    else -> 16.sp
}

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

คุณสามารถเรียกใช้ฟังก์ชัน mediaQuery และ derivedMediaQuery ในฟังก์ชันที่ใช้ร่วมกันได้เพื่อแสดงตัวอย่างคอมโพเนนต์ UI ข้อมูลโค้ดต่อไปนี้จะเลือกระหว่าง TabletopLayout กับ FlatLayout ตามค่าพารามิเตอร์ windowPosture หากต้องการแสดงตัวอย่าง TabletopLayout พารามิเตอร์ windowPosture ควรเป็น UiMediaScope.Posture.Tabletop

when {
    mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}

ฟังก์ชัน mediaQuery และ derivedMediaQuery จะประเมิน Lambda query ที่กำหนดไว้ภายในออบเจ็กต์ UiMediaScope ซึ่งมีให้เป็น LocalUiMediaScope.current คุณสามารถเขียนทับได้โดยทำตามขั้นตอนต่อไปนี้

  1. เปิดใช้ฟังก์ชัน mediaQuery
  2. กำหนดออบเจ็กต์ที่กำหนดเองซึ่งใช้ได้กับอินเทอร์เฟซ UiMediaScope
  3. ตั้งค่าออบเจ็กต์ที่กำหนดเองเป็น LocalUiMediaScope ด้วยฟังก์ชัน CompositionLocalProvider
  4. เรียกใช้ฟังก์ชันที่ใช้ร่วมกันได้เพื่อแสดงตัวอย่างใน Lambda เนื้อหาของฟังก์ชัน CompositionLocalProvider

คุณสามารถแสดงตัวอย่าง TabletopLayout ได้ด้วยตัวอย่างต่อไปนี้

@Preview
@Composable
fun PreviewLayoutForTabletop() {
    // Step 1: Enable the mediaQuery function
    ComposeUiFlags.isMediaQueryIntegrationEnabled = true

    val currentUiMediaScope = LocalUiMediaScope.current
    // Step 2: Define a custom object implementing the UiMediaScope interface.
    // The object overrides the windowPosture parameter.
    // The resolution of the remaining parameters is deferred to the currentUiMediaScope object.
    val uiMediaScope = remember(currentUiMediaScope) {
        object : UiMediaScope by currentUiMediaScope {
            override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop
        }
    }

    // Step 3: Set the object to the LocalUiMediaScope.
    CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) {
        // Step 4: Call the composable to preview.
        when {
            mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
            mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
            mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
        }
    }
}