ข้อควรพิจารณาอื่นๆ

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

การย้ายข้อมูลธีมของแอป

ดีไซน์ Material เป็นระบบการออกแบบที่แนะนำสำหรับการกำหนดธีมของแอป Android

สำหรับแอปที่อิงตามการดู จะมี Material ให้ดาวน์โหลด 3 เวอร์ชันดังนี้

  • ดีไซน์ Material 1 ที่ใช้ ไลบรารี AppCompat (นั่นคือ Theme.AppCompat.*)
  • ดีไซน์ Material 2 ที่ใช้องค์ประกอบ MDC-Android ไลบรารี (เช่น Theme.MaterialComponents.*)
  • ดีไซน์ Material 3 ที่ใช้องค์ประกอบ MDC-Android ไลบรารี (เช่น Theme.Material3.*)

สำหรับแอป Compose มี Material ให้ใช้งาน 2 เวอร์ชัน ดังนี้

  • ดีไซน์ Material 2 โดยใช้ ไลบรารีเขียนเนื้อหา (เช่น androidx.compose.material.MaterialTheme)
  • ดีไซน์ Material 3 ที่ใช้องค์ประกอบ ไลบรารีเขียน Material 3 (เช่น androidx.compose.material3.MaterialTheme)

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

เมื่อสร้างหน้าจอใหม่ใน Compose ไม่ว่าจะเป็น Material เวอร์ชันใดก็ตาม การออกแบบที่คุณใช้อยู่ อย่าลืมใช้ MaterialTheme ก่อน Composable ที่แสดง UI จากไลบรารี Material ของ Compose วัสดุ คอมโพเนนต์ (Button, Text ฯลฯ) ขึ้นอยู่กับ MaterialTheme ที่ใช้อยู่ และพฤติกรรมของผู้อ่านจะไม่มีทางกำหนดได้หากไม่มีความสามารถนี้

ทั้งหมด ตัวอย่าง Jetpack Compose ใช้ธีม Compose ที่กําหนดเองซึ่งสร้างจาก MaterialTheme

โปรดดูข้อมูลเพิ่มเติมที่ออกแบบระบบใน Compose และการย้ายข้อมูลธีม XML ไปยัง Compose

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

ทดสอบ UI การเขียน/มุมมองแบบผสมของคุณ

หลังจากย้ายส่วนต่างๆ ของแอปไปยัง Compose แล้ว การทดสอบมีความสำคัญอย่างยิ่งเพื่อให้มั่นใจว่า คุณยังไม่ได้หักอะไรเลย

เมื่อกิจกรรมหรือส่วนย่อยใช้การเขียน คุณต้องใช้ createAndroidComposeRule แทนการใช้ ActivityScenarioRule createAndroidComposeRule ผสานรวม ActivityScenarioRule ด้วย ComposeTestRule ที่ให้คุณทดสอบ Compose และ ดูโค้ดในเวลาเดียวกัน

class MyActivityTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test
    fun testGreeting() {
        val greeting = InstrumentationRegistry.getInstrumentation()
            .targetContext.resources.getString(R.string.greeting)

        composeTestRule.onNodeWithText(greeting).assertIsDisplayed()
    }
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับการทดสอบได้ที่การทดสอบเลย์เอาต์ของ Compose สำหรับ ความสามารถในการทำงานร่วมกันกับเฟรมเวิร์กการทดสอบ UI โปรดดู ความสามารถในการทำงานร่วมกับ Espresso และ ความสามารถในการทำงานร่วมกับ UiAutomator

การผสานรวม Compose กับสถาปัตยกรรมแอปที่มีอยู่

สถาปัตยกรรม Unidirectional Data Flow (UDF) จะทำงานร่วมกับ Compose ได้อย่างราบรื่น หากแอปใช้ประเภท รูปแบบสถาปัตยกรรมแบบเดิม อย่างเช่น ตัวนำเสนอมุมมองโมเดล (MVP) เราขอแนะนำให้คุณ ย้ายข้อมูลส่วนนั้นของ UI ไปยัง UDF ก่อนหรือในขณะที่ใช้ Compose

การใช้ ViewModel ในการเขียน

ถ้าคุณใช้คอมโพเนนต์สถาปัตยกรรม ไลบรารี ViewModel คุณจะเข้าถึง ViewModel จาก Composable โดย การเรียกฟังก์ชัน viewModel() ตามที่อธิบายไว้ในการเขียนและไลบรารีอื่นๆ

เมื่อนำการเขียนมาใช้ โปรดระมัดระวังการใช้ ViewModel ประเภทเดียวกันใน Composable ที่ต่างกันเนื่องจากองค์ประกอบ ViewModel จะเป็นไปตามขอบเขตวงจรการดู จะเป็นกิจกรรมโฮสต์ ส่วนย่อย หรือกราฟการนำทาง หาก ใช้ไลบรารีการนำทาง

ตัวอย่างเช่น หาก Composable โฮสต์อยู่ในกิจกรรม viewModel() จะเป็น แสดงผลอินสแตนซ์เดียวกันที่ถูกล้างไปเมื่อกิจกรรมเสร็จสิ้นเท่านั้น ในตัวอย่างต่อไปนี้ ผู้ใช้เดียวกัน ("user1") ได้รับการทักทายสองครั้งเนื่องจาก จะมีการนำอินสแตนซ์ GreetingViewModel เดียวกันมาใช้ซ้ำใน Composable ทั้งหมดภายใต้ กิจกรรมของโฮสต์ อินสแตนซ์ ViewModel รายการแรกที่สร้างจะมีการใช้ซ้ำในอินสแตนซ์อื่นๆ Composable

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

        setContent {
            MaterialTheme {
                Column {
                    GreetingScreen("user1")
                    GreetingScreen("user2")
                }
            }
        }
    }
}

@Composable
fun GreetingScreen(
    userId: String,
    viewModel: GreetingViewModel = viewModel(  
        factory = GreetingViewModelFactory(userId)  
    )
) {
    val messageUser by viewModel.message.observeAsState("")
    Text(messageUser)
}

class GreetingViewModel(private val userId: String) : ViewModel() {
    private val _message = MutableLiveData("Hi $userId")
    val message: LiveData<String> = _message
}

class GreetingViewModelFactory(private val userId: String) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return GreetingViewModel(userId) as T
    }
}

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

@Composable
fun MyApp() {
    NavHost(rememberNavController(), startDestination = "profile/{userId}") {
        /* ... */
        composable("profile/{userId}") { backStackEntry ->
            GreetingScreen(backStackEntry.arguments?.getString("userId") ?: "")
        }
    }
}

แหล่งข้อมูลความจริงของรัฐ

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

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

เขียนเป็นแหล่งข้อมูลที่ถูกต้อง

ใช้เมนู SideEffect Composable เพื่อเผยแพร่สถานะ Compose ไปยังโค้ดที่ไม่ใช่ Compose ในกรณีนี้ ค่า จะเก็บไว้ใน Composable ซึ่งจะส่งการอัปเดตสถานะ

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

@Composable
fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics {
    val analytics: FirebaseAnalytics = remember {
        FirebaseAnalytics()
    }

    // On every successful composition, update FirebaseAnalytics with
    // the userType from the current User, ensuring that future analytics
    // events have this metadata attached
    SideEffect {
        analytics.setUserProperty("userType", user.userType)
    }
    return analytics
}

ดูข้อมูลเพิ่มเติมได้ที่ผลข้างเคียงใน Compose

ดูระบบเป็นแหล่งข้อมูลที่ถูกต้อง

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

ในตัวอย่างต่อไปนี้ CustomViewGroup มี TextView และ ComposeView ที่มี TextField Composable ด้านใน TextView จำเป็นต้องแสดง เนื้อหาของสิ่งที่ผู้ใช้พิมพ์ใน TextField

class CustomViewGroup @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : LinearLayout(context, attrs, defStyle) {

    // Source of truth in the View system as mutableStateOf
    // to make it thread-safe for Compose
    private var text by mutableStateOf("")

    private val textView: TextView

    init {
        orientation = VERTICAL

        textView = TextView(context)
        val composeView = ComposeView(context).apply {
            setContent {
                MaterialTheme {
                    TextField(value = text, onValueChange = { updateState(it) })
                }
            }
        }

        addView(textView)
        addView(composeView)
    }

    // Update both the source of truth and the TextView
    private fun updateState(newValue: String) {
        text = newValue
        textView.text = newValue
    }
}

กำลังย้ายข้อมูล UI ที่ใช้ร่วมกัน

หากคุณค่อยๆ ย้ายข้อมูลไปยัง Compose คุณอาจต้องใช้ UI ที่ใช้ร่วมกัน ทั้งในระบบ "เขียน" และ "ดู" เช่น หากแอปของคุณมี คอมโพเนนต์ CallToActionButton ที่กำหนดเอง คุณอาจต้องใช้งานทั้งใน Compose และหน้าจอที่อิงตามการดู

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

หากต้องการใช้ Composable ในหน้าจอที่อิงตามการดู ให้สร้าง Wrapper มุมมองที่กำหนดเอง เริ่มจาก AbstractComposeView ใน Composable Content ที่ถูกลบล้าง วาง Composable ที่คุณสร้างขึ้นโดยรวมในธีม Compose ดังที่แสดงใน ตัวอย่างด้านล่าง

@Composable
fun CallToActionButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            containerColor = MaterialTheme.colorScheme.secondary
        ),
        onClick = onClick,
        modifier = modifier,
    ) {
        Text(text)
    }
}

class CallToActionViewButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : AbstractComposeView(context, attrs, defStyle) {

    var text by mutableStateOf("")
    var onClick by mutableStateOf({})

    @Composable
    override fun Content() {
        YourAppTheme {
            CallToActionButton(text, onClick)
        }
    }
}

โปรดสังเกตว่าพารามิเตอร์ Composable จะกลายเป็นตัวแปรที่เปลี่ยนแปลงได้ภายในที่กำหนดเอง ซึ่งทำให้มุมมอง CallToActionViewButton ที่กำหนดเองเป็นแบบเป่าลมและใช้งานได้ มุมมองดั้งเดิม ดูตัวอย่างของส่วนนี้ด้วย View Binding ด้านล่าง

class ViewBindingActivity : ComponentActivity() {

    private lateinit var binding: ActivityExampleBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.callToAction.apply {
            text = getString(R.string.greeting)
            onClick = { /* Do something */ }
        }
    }
}

หากคอมโพเนนต์ที่กำหนดเองมีสถานะที่เปลี่ยนแปลงได้ โปรดดูแหล่งที่มาของสถานะของ ความจริง

ให้ความสำคัญกับสถานะการแยกออกจากงานนำเสนอ

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

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

ในทางตรงกันข้าม Compose ทำให้การแสดง Composable ที่แตกต่างกันโดยสิ้นเชิงเป็นเรื่องง่าย โดยใช้ตรรกะตามเงื่อนไขใน Kotlin

@Composable
fun MyComposable(showCautionIcon: Boolean) {
    if (showCautionIcon) {
        CautionIcon(/* ... */)
    }
}

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

การแยกการจัดการสถานะและตรรกะการนำเสนอออกจากกันอย่างชัดเจน ทำให้คุณสามารถ เปลี่ยนวิธีแสดงเนื้อหาเป็นการแปลงสถานะเป็น UI ได้อย่างอิสระ การอยู่ สามารถยกสถานะเมื่อต้องการ ทำให้ Composable นำมาใช้ซ้ำได้มากขึ้นเนื่องจาก การเป็นเจ้าของในแต่ละรัฐนั้นยืดหยุ่นกว่า

โปรโมตส่วนประกอบที่ห่อหุ้มและนำมาใช้ใหม่ได้

องค์ประกอบ View มักทราบตำแหน่งที่ตั้งของสิ่งนั้น เช่น ภายใน Activity Dialog, Fragment หรือที่อื่นภายในลําดับชั้น View อื่น เพราะ ไฟล์มักพองขึ้นจากไฟล์เลย์เอาต์แบบคงที่ ซึ่งเป็นโครงสร้างโดยรวมของ View มีแนวโน้มที่จะตายตัวมาก ซึ่งทำให้เกิดการเชื่อมต่อที่แน่นแฟ้นขึ้น View จะเปลี่ยนแปลงหรือนำมาใช้ซ้ำได้ยากขึ้น

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

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

@Composable
fun AScreen() {
    var isEnabled by rememberSaveable { mutableStateOf(false) }

    Column {
        ImageWithEnabledOverlay(isEnabled)
        ControlPanelWithToggle(
            isEnabled = isEnabled,
            onEnabledChanged = { isEnabled = it }
        )
    }
}

ในตัวอย่างข้างต้น ทั้ง 3 ส่วนจะห่อหุ้มมากขึ้นและมีคู่น้อยกว่า

  • ImageWithEnabledOverlay เพียงแต่อยากรู้ว่า isEnabled ปัจจุบันเป็นอย่างไร แล้วตอนนี้ ไม่จำเป็นต้องทราบว่ามี ControlPanelWithToggle อยู่ หรือ แม้แต่วิธีที่ควบคุมได้

  • ControlPanelWithToggle ไม่ทราบว่ามี ImageWithEnabledOverlay อยู่ การแสดง isEnabled อาจไม่มีเลย อย่างน้อย 1 วิธี และ ControlPanelWithToggle ไม่จำเป็นต้องเปลี่ยนแปลง

  • สำหรับผู้ปกครอง ไม่ว่า ImageWithEnabledOverlay จะฝังลึกเพียงใดก็ตาม หรือ ControlPanelWithToggle เด็กเหล่านั้น สามารถทำให้การเปลี่ยนแปลงเป็นภาพเคลื่อนไหว สลับเนื้อหาหรือส่งต่อเนื้อหาให้เด็กคนอื่นๆ

รูปแบบนี้เรียกว่าการกลับการควบคุมซึ่งอ่านเพิ่มเติมได้ ในเอกสารประกอบของ CompositionLocal

การจัดการการเปลี่ยนแปลงขนาดหน้าจอ

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

นอกจากนี้ โปรดดูหัวข้อรองรับหน้าจอขนาดต่างๆ เพื่อเรียนรู้เทคนิคต่างๆ ที่ Compose มีให้ในการสร้าง UI แบบปรับอัตโนมัติ

การเลื่อนแบบฝังที่มีมุมมอง

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

เขียนในภาษาRecyclerView

Composable ใน RecyclerView มีประสิทธิภาพตั้งแต่ RecyclerView เวอร์ชัน 1.3.0-alpha02 ตรวจสอบว่าใช้เวอร์ชัน 1.3.0-alpha02 เป็นอย่างต่ำ RecyclerViewเพื่อดูสิทธิประโยชน์เหล่านั้น

การทำงานร่วมกันของ WindowInsets กับ View

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

ตัวอย่างเช่น หากเลย์เอาต์ด้านนอกสุดเป็นเลย์เอาต์ของ Android View คุณควรทำดังนี้ ใช้ส่วนที่แทรกในระบบมุมมอง และละเว้นสำหรับการเขียน หรือถ้าเลย์เอาต์ด้านนอกสุดเป็น Composable คุณควรใช้ สิ่งที่แทรกใน Compose และแทรก Composable ของ AndroidView ตามนั้น

ตามค่าเริ่มต้น ComposeView แต่ละรายการจะใช้ค่าที่แทรกทั้งหมด ระดับการใช้งาน WindowInsetsCompat หากต้องการเปลี่ยนลักษณะการทำงานเริ่มต้นนี้ ให้ตั้งค่า ComposeView.consumeWindowInsets ไปยัง false

โปรดอ่านข้อมูลเพิ่มเติมในเอกสารประกอบ WindowInsets ใน Compose