ตรวจสอบว่า UI ทำงานร่วมกับส่วนแทรกของหน้าต่างได้

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

ตัวอย่างเช่น นี่เป็นวิธีที่ง่ายที่สุดในการใส่ส่วนแทรกในเนื้อหาของแอปทั้งแอป

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

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

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

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

ตัวปรับระยะห่างจากขอบ

Modifier.windowInsetsPadding(windowInsets: WindowInsets) ใช้ส่วนแทรกของหน้าต่างที่ระบุเป็นระยะห่างจากขอบ โดยทํางานเหมือนกับที่ Modifier.padding จะทำ เช่น Modifier.windowInsetsPadding(WindowInsets.safeDrawing) ใช้ส่วนแทรกที่ปลอดภัยของภาพวาดเป็นระยะห่างจากขอบทั้ง 4 ด้าน

นอกจากนี้ยังมีเมธอดยูทิลิตีในตัวหลายรายการสําหรับประเภทการฝังที่พบบ่อยที่สุด Modifier.safeDrawingPadding() เป็นวิธีหนึ่งซึ่งเทียบเท่ากับ Modifier.windowInsetsPadding(WindowInsets.safeDrawing) ก็มีตัวปรับเปลี่ยนที่คล้ายกันสำหรับประเภทอื่นๆ ของส่วนแทรก

ตัวแก้ไขขนาดของส่วนแทรก

ตัวแก้ไขต่อไปนี้จะใช้จำนวนส่วนโค้งมนของหน้าต่างโดยกำหนดขนาดของคอมโพเนนต์ให้เท่ากับขนาดของส่วนโค้งมน

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

ใช้ด้านเริ่มต้นของ windowInsets เป็นความกว้าง (เช่น Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

ใช้ด้านท้ายของ windowInsets เป็นความกว้าง (เช่น Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

ใช้ด้านข้างบนของ windowInsets เป็นค่าความสูง (เช่น Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

ใช้ด้านล่างของ windowInsets เป็นค่าความสูง (เช่น Modifier.height)

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

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

การใช้งานที่ฝัง

ตัวแก้ไขระยะห่างจากขอบใน (windowInsetsPadding และตัวช่วย เช่น safeDrawingPadding) จะใช้ส่วนของส่วนที่เยื้องเข้ามาซึ่งใช้เป็นระยะห่างจากขอบโดยอัตโนมัติ เมื่อเข้าไปในลําดับชั้นองค์ประกอบที่ลึกขึ้น ตัวแก้ไขระยะห่างจากขอบด้านในแบบฝังและตัวแก้ไขขนาดระยะห่างจากขอบด้านในจะทราบว่ามีการใช้ระยะห่างจากขอบด้านในบางส่วนโดยตัวแก้ไขระยะห่างจากขอบด้านในแบบด้านนอกแล้ว และหลีกเลี่ยงการใช้ระยะห่างจากขอบด้านในส่วนเดียวกันมากกว่า 1 ครั้ง ซึ่งจะทำให้มีช่องว่างมากเกินไป

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

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

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

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

เมื่อ IME ปิดอยู่ ตัวแก้ไข imePadding() จะไม่ใช้ระยะห่างจากขอบ เนื่องจาก IME ไม่มีความสูง เนื่องจากตัวแก้ไข imePadding() ไม่ได้ใช้ระยะห่างจากขอบ ระบบจะไม่ใช้ส่วนตัด และส่วนสูงของ Spacer จะเท่ากับขนาดของด้านด้านล่างของแถบระบบ

เมื่อ IME เปิดขึ้น ส่วนที่แทรกของ IME จะเคลื่อนไหวเพื่อให้ตรงกับขนาดของ IME และตัวแก้ไข imePadding() จะเริ่มใช้ระยะห่างจากด้านล่างเพื่อปรับขนาด LazyColumn เมื่อ IME เปิดขึ้น เมื่อตัวแก้ไข imePadding() เริ่มใช้ระยะห่างจากขอบด้านล่าง ก็จะเริ่มใช้ระยะห่างจากขอบในจำนวนนั้นด้วย ดังนั้น ความสูงของ Spacer จึงเริ่มลดลง เนื่องจากตัวดัดแปลง imePadding() ได้ใช้การเว้นวรรคสำหรับแถบระบบแล้ว เมื่อตัวแก้ไข imePadding() ใช้ระยะห่างจากขอบด้านล่างที่มากกว่าแถบระบบ ความสูงของ Spacer จะเท่ากับ 0

เมื่อ IME ปิดลง การเปลี่ยนแปลงจะเกิดขึ้นในลักษณะกลับกัน โดย Spacer จะเริ่มขยายจากระดับความสูง 0 เมื่อ imePadding() มีขนาดน้อยกว่าแถบด้านล่างของระบบ จนในที่สุด Spacer จะเท่ากับความสูงของแถบด้านล่างของระบบเมื่อ IME แสดงภาพเคลื่อนไหวจนหมด

รูปที่ 2 คอลัมน์แบบ Lazy จากขอบถึงขอบที่มี TextField

ลักษณะการทำงานนี้เกิดขึ้นจากการสื่อสารระหว่างตัวปรับเปลี่ยน windowInsetsPadding ทั้งหมด และอาจได้รับอิทธิพลจากวิธีอื่นๆ อีก 2 วิธี

Modifier.consumeWindowInsets(insets: WindowInsets) ยังใช้ส่วนเกินในลักษณะเดียวกับ Modifier.windowInsetsPadding แต่ไม่ได้ใช้ส่วนเกินที่ใช้เป็นระยะห่างจากขอบ ซึ่งมีประโยชน์เมื่อใช้ร่วมกับตัวแก้ไขขนาดของส่วนตัดเพื่อบ่งบอกให้องค์ประกอบพี่น้องทราบว่ามีการใช้ส่วนตัดจำนวนหนึ่งแล้ว

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues) ทำงานคล้ายกับเวอร์ชันที่มีอาร์กิวเมนต์ WindowInsets มาก แต่จะใช้ PaddingValues ที่กำหนดเอง ซึ่งมีประโยชน์ในการแจ้งให้องค์ประกอบย่อยทราบเมื่อมีการใส่การเว้นวรรคหรือระยะห่างโดยกลไกอื่นนอกเหนือจากตัวแก้ไขการเว้นวรรคที่ฝัง เช่น Modifier.padding ธรรมดาหรือตัวเว้นวรรคความสูงคงที่

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

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

ระยะขอบและระยะของ Jetpack Compose

Compose ใช้ API หลักของ AndroidX ที่อยู่เบื้องหลังเพื่ออัปเดตและแสดงภาพเคลื่อนไหวของส่วนตัด ซึ่งใช้ API ของแพลตฟอร์มที่อยู่เบื้องหลังซึ่งจัดการส่วนตัด ลักษณะการทํางานของแพลตฟอร์มนี้ทําให้ส่วนตัดสัมพันธ์กับระยะของ Jetpack Compose เป็นพิเศษ

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