แม้ว่าการย้ายข้อมูลจากมุมมองไปยัง Compose จะเกี่ยวข้องกับ UI เท่านั้น แต่ก็มีหลายๆ สิ่งที่ต้องพิจารณาเพื่อให้การย้ายข้อมูลมีความปลอดภัยและเพิ่มขึ้นอย่างต่อเนื่อง หน้านี้มีสิ่งที่ควรพิจารณาขณะย้ายข้อมูลแอปที่อิงตาม View ไปยัง Compose
การย้ายข้อมูลธีมของแอป
การออกแบบ Material Design เป็นระบบการออกแบบที่แนะนำสำหรับธีมแอป Android
สำหรับแอปที่อิงตามการดู จะมี Material ให้ดาวน์โหลด 3 เวอร์ชันดังนี้
- Material Design 1 โดยใช้ไลบรารี AppCompat (เช่น
Theme.AppCompat.*
) - Material Design 2 โดยใช้ไลบรารี MDC-Android (เช่น
Theme.MaterialComponents.*
) - ดีไซน์ Material 3 โดยใช้ไลบรารี
MDC-Android (เช่น
Theme.Material3.*
)
สำหรับแอป Compose วัสดุมี 2 เวอร์ชัน ได้แก่
- ดีไซน์ Material 2 โดยใช้ไลบรารี
Compose Material
(เช่น
androidx.compose.material.MaterialTheme
) - ดีไซน์ Material 3 โดยใช้ไลบรารี
Compose Material 3
(เช่น
androidx.compose.material3.MaterialTheme
)
เราขอแนะนำให้ใช้เวอร์ชันล่าสุด (Material 3) หากระบบการออกแบบของแอปรองรับการใช้งานเวอร์ชันดังกล่าว เรามีคำแนะนำในการย้ายข้อมูลสำหรับทั้ง Views และ Compose ดังนี้
เมื่อสร้างหน้าจอใหม่ใน Compose ไม่ว่าคุณจะใช้ Material Design เวอร์ชันใดก็ตาม โปรดตรวจสอบว่าคุณใช้ MaterialTheme
ก่อนคอมโพสิเบิลที่แสดง UI จากคลัง Material ของ Compose คอมโพเนนต์ของวัสดุ (Button
, Text
ฯลฯ) ขึ้นอยู่กับว่ามี MaterialTheme
อยู่หรือไม่ และลักษณะการทํางานจะไม่มีการกําหนดหากไม่มี MaterialTheme
ตัวอย่าง Jetpack Compose ทั้งหมดใช้ธีม Compose ที่กําหนดเองซึ่งสร้างขึ้นจาก MaterialTheme
ดูข้อมูลเพิ่มเติมที่ระบบการออกแบบใน Compose และการย้ายธีม XML ไปยัง Compose
การไปยังรายการต่างๆ
หากคุณใช้คอมโพเนนต์การนำทางในแอป โปรดดูข้อมูลเพิ่มเติมในการไปยังส่วนต่างๆ ด้วย Compose - การทํางานร่วมกัน และย้ายข้อมูลการนำทางของ Jetpack ไปยัง Navigation Compose
ทดสอบ UI ของ Compose/Views แบบผสม
หลังจากย้ายข้อมูลบางส่วนของแอปไปยัง Compose แล้ว การทดสอบเป็นขั้นตอนสําคัญเพื่อให้แน่ใจว่าคุณไม่ได้ทําให้แอปเสียหาย
เมื่อกิจกรรมหรือแฟรกเมนต์ใช้ Compose คุณต้องใช้ createAndroidComposeRule
แทนการใช้ ActivityScenarioRule
createAndroidComposeRule
ผสานรวม ActivityScenarioRule
กับ ComposeTestRule
ที่ช่วยให้คุณทดสอบโค้ด Compose และ View ได้ในเวลาเดียวกัน
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() } }
ดูข้อมูลเพิ่มเติมเกี่ยวกับการทดสอบได้ที่การทดสอบเลย์เอาต์การเขียน หากต้องการทำงานร่วมกับเฟรมเวิร์กการทดสอบ UI โปรดดูความสามารถในการทำงานร่วมกับ Espresso และความสามารถในการทำงานร่วมกับ UiAutomator
การผสานรวม Compose เข้ากับสถาปัตยกรรมแอปที่มีอยู่
รูปแบบสถาปัตยกรรม Unidirectional Data Flow (UDF) ทำงานร่วมกับ Compose ได้อย่างราบรื่น หากแอปใช้รูปแบบสถาปัตยกรรมประเภทอื่นๆ แทน เช่น Model View Presenter (MVP) เราขอแนะนำให้คุณย้ายข้อมูล UI ในส่วนนั้นไปยัง UDF ก่อนหรือขณะที่ใช้งาน Compose
การใช้ ViewModel
ในเครื่องมือเขียน
หากใช้ไลบรารี Architecture Components
ViewModel
คุณจะเข้าถึง ViewModel
จากคอมโพสิเบิลใดก็ได้โดยเรียกใช้ฟังก์ชัน viewModel()
ตามที่อธิบายไว้ในCompose และไลบรารีอื่นๆ
เมื่อใช้ Compose ให้ระมัดระวังในการใช้ ViewModel
ประเภทเดียวกันในคอมโพสิเบิลต่างๆ เนื่องจากองค์ประกอบ ViewModel
จะเป็นไปตามขอบเขตวงจรชีวิตของ View ขอบเขตจะเป็นกิจกรรมของโฮสต์ เศษ หรือกราฟการนําทาง หากใช้คลังการนําทาง
เช่น หากคอมโพสิเบิลโฮสต์อยู่ในกิจกรรม viewModel()
จะแสดงอินสแตนซ์เดียวกันเสมอ ซึ่งระบบจะล้างออกก็ต่อเมื่อกิจกรรมเสร็จสิ้น
ในตัวอย่างต่อไปนี้ ระบบจะทักทายผู้ใช้รายเดียวกัน ("user1") 2 ครั้ง เนื่องจากมีการใช้อินสแตนซ์ GreetingViewModel
เดียวกันซ้ำในคอมโพสิเบิลทั้งหมดภายใต้กิจกรรมของโฮสต์ อินสแตนซ์ 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
ด้วย คอมโพสิเบิลที่เป็นปลายทางในกราฟการนำทางจึงมีอินสแตนซ์ ViewModel
อื่น
ในกรณีนี้ ViewModel
จะกำหนดขอบเขตตามวงจรชีวิตของปลายทาง และระบบจะล้าง ViewModel
เมื่อนำปลายทางออกจากกองซ้อนด้านหลัง ในตัวอย่างต่อไปนี้ เมื่อผู้ใช้ไปยังหน้าจอโปรไฟล์ ระบบจะสร้างอินสแตนซ์ใหม่ของ GreetingViewModel
@Composable fun MyApp() { NavHost(rememberNavController(), startDestination = "profile/{userId}") { /* ... */ composable("profile/{userId}") { backStackEntry -> GreetingScreen(backStackEntry.arguments?.getString("userId") ?: "") } } }
แหล่งข้อมูลที่เป็นความจริงของรัฐ
เมื่อคุณใช้งาน Compose ในส่วนหนึ่งของ UI อาจเป็นไปได้ที่การเขียนและโค้ดของระบบ View ต้องแชร์ข้อมูลกัน เราขอแนะนําให้คุณรวมสถานะที่แชร์นั้นไว้ในคลาสอื่นที่เป็นไปตามแนวทางปฏิบัติแนะนําของ UDF ซึ่งทั้ง 2 แพลตฟอร์มใช้ เช่น ใน ViewModel
ที่แสดงสตรีมข้อมูลที่แชร์เพื่อส่งการอัปเดตข้อมูล
อย่างไรก็ตาม ข้อมูลนั้นเป็นไปไม่ได้เสมอไปหากข้อมูลที่จะแชร์นั้นเปลี่ยนแปลงไม่ได้หรือเชื่อมโยงกับองค์ประกอบ UI อย่างแน่นหนา ในกรณีนี้ ระบบหนึ่งต้องเป็นแหล่งข้อมูลที่ถูกต้อง และระบบนั้นต้องแชร์ข้อมูลอัปเดตไปยังอีกระบบหนึ่ง ตามหลักการทั่วไป องค์ประกอบใดก็ตามที่อยู่ใกล้กับรูทของลำดับชั้น UI ควรเป็นเจ้าของแหล่งข้อมูลที่ถูกต้อง
เขียนเป็นแหล่งข้อมูลที่เชื่อถือได้
ใช้ SideEffect
แบบคอมโพสิเบิลเพื่อเผยแพร่สถานะ Compose ไปยังโค้ดที่ไม่ใช่ Compose ในกรณีนี้ ระบบจะเก็บแหล่งข้อมูลที่เป็นความจริงไว้ในคอมโพสิเบิล ซึ่งจะส่งการอัปเดตสถานะ
ตัวอย่างเช่น ไลบรารีข้อมูลวิเคราะห์อาจช่วยให้คุณแบ่งกลุ่มประชากรผู้ใช้ได้โดยแนบข้อมูลเมตาที่กําหนดเอง (พร็อพเพอร์ตี้ผู้ใช้ในตัวอย่างนี้) ไปกับเหตุการณ์การวิเคราะห์ที่ตามมาทั้งหมด หากต้องการสื่อสารประเภทผู้ใช้ของผู้ใช้ปัจจุบันกับคลังข้อมูลวิเคราะห์ ให้ใช้ 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
ดูระบบเป็นแหล่งข้อมูลที่ถูกต้อง
หากระบบมุมมองเป็นเจ้าของสถานะและแชร์กับ Compose เราขอแนะนำให้คุณรวมสถานะไว้ในออบเจ็กต์ mutableStateOf
เพื่อให้ Compose ทำงานได้อย่างปลอดภัยในเธรด หากใช้แนวทางนี้ ฟังก์ชันคอมโพสิเบิลจะทำงานได้ง่ายขึ้นเนื่องจากไม่มีแหล่งข้อมูลที่เป็นความจริงอีกต่อไป แต่ระบบมุมมองต้องอัปเดตสถานะที่เปลี่ยนแปลงได้และมุมมองที่ใช้สถานะนั้น
ในตัวอย่างต่อไปนี้ CustomViewGroup
มี TextView
และ ComposeView
ที่มี TextField
อยู่ภายใน 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 ที่แชร์ทั้งใน Compose และระบบ View เช่น หากแอปของคุณมีคอมโพเนนต์ CallToActionButton
ที่กําหนดเอง คุณอาจต้องใช้คอมโพเนนต์นั้นทั้งในหน้าจอแบบคอมโพสิทและหน้าจอแบบ View
ใน Compose องค์ประกอบ UI ที่แชร์จะกลายเป็นคอมโพสิเบิลที่นํากลับมาใช้ใหม่ได้ทั่วทั้งแอป ไม่ว่าองค์ประกอบนั้นจะจัดสไตล์โดยใช้ XML หรือเป็นมุมมองที่กําหนดเองก็ตาม เช่น คุณอาจสร้างคอมโพสิเบิล CallToActionButton
สําหรับคอมโพเนนต์คำกระตุ้นให้ดำเนินการ Button
ที่กําหนดเอง
หากต้องการใช้คอมโพสิเบิลในหน้าจอแบบ View ให้สร้าง 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) } } }
โปรดทราบว่าพารามิเตอร์แบบคอมโพสิเบิลจะกลายเป็นตัวแปรที่เปลี่ยนแปลงได้ภายในมุมมองที่กําหนดเอง วิธีนี้จะทำให้มุมมอง CallToActionViewButton
ที่กําหนดเองขยายและใช้งานได้ เช่นเดียวกับมุมมองแบบดั้งเดิม ดูตัวอย่างการใช้การเชื่อมโยงมุมมองด้านล่าง
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 ช่วยให้การแสดงคอมโพสิเบิลที่แตกต่างกันโดยสิ้นเชิงเป็นเรื่องง่ายโดยใช้ตรรกะแบบมีเงื่อนไขใน Kotlin ดังนี้
@Composable fun MyComposable(showCautionIcon: Boolean) { if (showCautionIcon) { CautionIcon(/* ... */) } }
CautionIcon
ไม่จำเป็นต้องรู้หรือสนใจว่าเหตุใดจึงมีการแสดง CautionIcon
ขึ้น และไม่มีแนวคิดของ visibility
นั่นคือ CautionIcon
อยู่ในองค์ประกอบหรือไม่อยู่ในองค์ประกอบ
การแยกการจัดการสถานะและตรรกะการแสดงผลอย่างเรียบร้อยช่วยให้คุณเปลี่ยนวิธีแสดงเนื้อหาเป็นการแปลงสถานะเป็น UI ได้อย่างอิสระมากขึ้น การสามารถยกสถานะได้เมื่อต้องการทำให้ Composable ใช้งานซ้ำได้มากขึ้นเนื่องจากการเป็นเจ้าของระดับรัฐมีความยืดหยุ่นมากกว่า
โปรโมตชิ้นส่วนที่ห่อหุ้มไว้และนำมาใช้ซ้ำได้
องค์ประกอบ View
มักจะทราบตำแหน่งที่ตัวเองอยู่ เช่น ภายใน Activity
, Dialog
, Fragment
หรือภายในลําดับชั้น View
อื่น เนื่องจากไฟล์เหล่านี้มักสร้างขึ้นจากไฟล์เลย์เอาต์แบบคงที่ โครงสร้างโดยรวมของ View
จึงมีแนวโน้มที่จะเป็นแบบแผนมาก ซึ่งส่งผลให้มีการเชื่อมต่อที่เหนียวแน่นขึ้นและทำให้เปลี่ยนหรือนำ View
มาใช้ซ้ำได้ยากขึ้น
ตัวอย่างเช่น View
ที่กําหนดเองอาจถือว่ามีมุมมองย่อยของประเภทหนึ่งๆ ที่มีรหัสหนึ่งๆ และเปลี่ยนพร็อพเพอร์ตี้เพื่อตอบสนองการดําเนินการบางอย่างโดยตรง วิธีนี้จะเชื่อมโยงองค์ประกอบ View
เหล่านั้นเข้าด้วยกันอย่างเหนียวแน่น โดย View
ที่กำหนดเองอาจขัดข้องหรือเสียหายหากไม่พบองค์ประกอบย่อย และองค์ประกอบย่อยอาจนำกลับมาใช้ซ้ำไม่ได้หากไม่มีรายการหลัก View
ที่กำหนดเอง
ปัญหานี้เกิดขึ้นน้อยลงใน Compose เมื่อใช้คอมโพสิเบิลที่ใช้ซ้ำได้ คอมโพเนนต์หลักสามารถระบุสถานะและการเรียกกลับได้ง่ายๆ คุณจึงเขียนคอมโพสิเบิลที่นํากลับมาใช้ซ้ำได้โดยไม่ต้องทราบว่าจะใช้คอมโพสิเบิลนั้นที่ใด
@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 แบบปรับเปลี่ยนได้
การเลื่อนที่ฝังไว้ด้วย Views
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเปิดใช้การทำงานร่วมกันในการเลื่อนแบบซ้อนกันระหว่างองค์ประกอบ View ที่เลื่อนได้และคอมโพสิชันที่เลื่อนได้ ซึ่งซ้อนกันทั้ง 2 ทิศทางได้ในส่วนการทำงานร่วมกันในการเลื่อนแบบซ้อนกัน
เขียนใน RecyclerView
Composable ใน RecyclerView
มีประสิทธิภาพตั้งแต่ RecyclerView
เวอร์ชัน 1.3.0-alpha02 ตรวจสอบว่าคุณใช้ RecyclerView
เวอร์ชัน 1.3.0-alpha02 เวอร์ชัน 1.3.0-alpha02 เป็นอย่างน้อยเพื่อดูสิทธิประโยชน์เหล่านั้น
WindowInsets
ทำงานร่วมกับข้อมูลพร็อพเพอร์ตี้
คุณอาจต้องลบล้างส่วนเริ่มต้นเมื่อหน้าจอมีทั้งมุมมองและโค้ด Compose ในลำดับชั้นเดียวกัน ในกรณีนี้ คุณต้องระบุอย่างชัดเจนว่าชิ้นงานใดควรใช้ส่วนแทรก และชิ้นงานใดควรละเว้น
ตัวอย่างเช่น หากเลย์เอาต์ด้านนอกสุดเป็นเลย์เอาต์ของ Android View คุณควรใช้งานส่วนนั้นในระบบมุมมองและไม่ต้องสนใจ Compose
หรือหากเลย์เอาต์ด้านนอกสุดเป็นคอมโพสิเบิล คุณควรใช้ส่วนเยื้องใน Compose และเพิ่มระยะห่างให้กับคอมโพสิเบิล AndroidView
ตามนั้น
โดยค่าเริ่มต้น ComposeView
แต่ละรายการจะใช้อินเซ็ตทั้งหมดในระดับการบริโภค WindowInsetsCompat
หากต้องการเปลี่ยนลักษณะการทำงานเริ่มต้นนี้ ให้ตั้งค่า ComposeView.consumeWindowInsets
เป็น false
อ่านข้อมูลเพิ่มเติมได้ที่เอกสารประกอบเกี่ยวกับ WindowInsets
ใน Compose
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- แสดงอีโมจิ
- Material Design 2 ใน Compose
- ส่วนที่เว้นไว้ในหน้าต่างในเครื่องมือเขียน