ค้นหาข้อมูลสำหรับเลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่ด้วย 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()
    }
}

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

คุณสามารถกำหนดเงื่อนไขเป็นแลมบ์ดาที่ประเมินภายใน 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 จะประเมินแลมบ์ดา query ด้วยออบเจ็กต์ UiMediaScope ที่อัปเดตแล้ว และแสดงผลค่าบูลีน ตัวอย่างเช่น ข้อมูลโค้ดต่อไปนี้จะเลือกระหว่าง TabletopLayout กับ FlatLayout โดยอิงตามค่าพารามิเตอร์ windowPosture

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

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

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

ฟังก์ชัน derivedMediaQuery จะประเมินแลมบ์ดา 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 อธิบายความแม่นยำของอุปกรณ์ชี้ตำแหน่งที่ใช้ได้ เช่น เมาส์และหน้าจอสัมผัส มีค่า 4 ค่าที่กำหนดไว้ในคลาส UiMediaScope.PointerPrecision ได้แก่ Fine, Coarse, Blunt และ None None หมายความว่าไม่มีอุปกรณ์ชี้ตำแหน่งที่พร้อมใช้งาน ความแม่นยำมีตั้งแต่สูงสุดไปจนถึงต่ำสุดตามลำดับต่อไปนี้ Fine, Coarse และ Blunt

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

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

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 จะแสดงค่าประมาณของระยะการดูโดยอิงตามประเภทอุปกรณ์และบริบทการใช้งานทั่วไป

มีค่า 3 ค่าที่กำหนดไว้ในคลาส UiMediaScope.ViewingDistance ได้แก่ 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 จะประเมินแลมบ์ดา query ที่ระบุภายในออบเจ็กต์ UiMediaScope ซึ่งระบุเป็น LocalUiMediaScope.current คุณลบล้างได้โดยทำตามขั้นตอนต่อไปนี้

  1. เปิดใช้ฟังก์ชัน mediaQuery
  2. กำหนดออบเจ็กต์ที่กำหนดเองซึ่งใช้อินเทอร์เฟซ UiMediaScope
  3. ตั้งค่าออบเจ็กต์ที่กำหนดเองเป็น LocalUiMediaScope ด้วยฟังก์ชัน CompositionLocalProvider
  4. เรียกใช้ Composable เพื่อแสดงตัวอย่างใน 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()
        }
    }
}