แม้ว่าการย้ายข้อมูลจาก Views ไปยัง Compose จะเกี่ยวข้องกับ UI โดยเฉพาะ แต่ก็มีหลายสิ่งที่คุณต้องคำนึงถึงเพื่อทำการย้ายข้อมูลอย่างปลอดภัยและค่อยๆ เป็นค่อยไป หน้านี้มีข้อควรพิจารณาบางประการขณะย้ายข้อมูลแอปที่อิงตาม View ไปยัง Compose
การย้ายข้อมูลธีมของแอป
Material Design เป็นระบบการออกแบบที่แนะนำสำหรับการกำหนดธีมแอป Android
สำหรับแอปที่อิงตาม View จะมี Material 3 เวอร์ชันให้ใช้งาน ดังนี้
- Material Design 1 ที่ใช้ไลบรารี
AppCompat (เช่น
Theme.AppCompat.*
) - Material Design 2 โดยใช้ไลบรารี
MDC-Android (เช่น
Theme.MaterialComponents.*
) - Material Design 3 โดยใช้ไลบรารี
MDC-Android (เช่น
Theme.Material3.*
)
สำหรับแอป Compose จะมี Material 2 เวอร์ชันให้ใช้งาน ได้แก่
- Material Design 2 โดยใช้ไลบรารี
Compose Material
(เช่น
androidx.compose.material.MaterialTheme
) - Material Design 3 โดยใช้ไลบรารี
Compose Material 3
(เช่น
androidx.compose.material3.MaterialTheme
)
เราขอแนะนำให้ใช้เวอร์ชันล่าสุด (Material 3) หากระบบการออกแบบของแอป พร้อมที่จะทำเช่นนั้น มีคำแนะนำในการย้ายข้อมูลสำหรับทั้ง Views และ Compose ดังนี้
- สื่อการเรียนการสอน 1 ถึงสื่อการเรียนการสอน 2 ในมุมมอง
- Material 2 to Material 3 in Views
- วัสดุ 2 ถึงวัสดุ 3 ในการเขียน
เมื่อสร้างหน้าจอใหม่ใน Compose ไม่ว่าคุณจะใช้ Material
Design เวอร์ชันใดก็ตาม ให้ตรวจสอบว่าคุณได้ใช้ MaterialTheme
ก่อน
Composables ที่ปล่อย UI จากไลบรารี Material ของ Compose คอมโพเนนต์ Material (Button
, Text
ฯลฯ) ขึ้นอยู่กับMaterialTheme
ที่มีอยู่
และจะไม่มีการกำหนดลักษณะการทำงานหากไม่มีคอมโพเนนต์ดังกล่าว
ตัวอย่าง Jetpack Compose ทั้งหมด
ใช้ธีม Compose ที่กำหนดเองซึ่งสร้างขึ้นบน MaterialTheme
ดูข้อมูลเพิ่มเติมได้ที่ระบบการออกแบบใน Compose และการย้ายข้อมูลธีม XML ไปยัง Compose
การไปยังรายการต่างๆ
หากคุณใช้คอมโพเนนต์การนำทางในแอป โปรดดูข้อมูลเพิ่มเติมที่การไปยังส่วนต่างๆ ด้วย Compose - การทำงานร่วมกันและย้ายข้อมูลการนำทางของ Jetpack ไปยังการนำทางด้วย Compose
ทดสอบ UI แบบผสม Compose/Views
หลังจากย้ายข้อมูลบางส่วนของแอปไปยัง Compose แล้ว การทดสอบเป็นสิ่งสำคัญเพื่อให้แน่ใจว่า คุณไม่ได้ทำให้สิ่งใดเสียหาย
เมื่อกิจกรรมหรือ Fragment ใช้ 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() } }
ดูข้อมูลเพิ่มเติมเกี่ยวกับการทดสอบได้ที่การทดสอบเลย์เอาต์ Compose ดูการทำงานร่วมกับเฟรมเวิร์กการทดสอบ UI ได้ที่การทำงานร่วมกับ Espresso และการทำงานร่วมกับ UiAutomator
การผสานรวม Compose กับสถาปัตยกรรมแอปที่มีอยู่
สถาปัตยกรรมการไหลของข้อมูลแบบทางเดียว (UDF) และรูปแบบต่างๆ ทำงานร่วมกับ Compose ได้อย่างราบรื่น หากแอปใช้รูปแบบสถาปัตยกรรมประเภทอื่นแทน เช่น Model View Presenter (MVP) เราขอแนะนำให้คุณ ย้ายข้อมูลส่วนนั้นของ UI ไปยัง UDF ก่อนหรือขณะใช้ Compose
การใช้ ViewModel
ในการเขียน
หากใช้ไลบรารี Architecture Components
ViewModel
คุณจะเข้าถึง
ViewModel
จาก Composable ใดก็ได้โดย
เรียกใช้ฟังก์ชัน
viewModel()
ตามที่อธิบายไว้ใน Compose และไลบรารีอื่นๆ
เมื่อใช้ Compose โปรดระมัดระวังในการใช้ประเภท ViewModel
เดียวกันใน
Composables ที่แตกต่างกัน เนื่องจากองค์ประกอบ ViewModel
จะเป็นไปตามขอบเขตวงจรของ View
ขอบเขตจะเป็นกิจกรรมโฮสต์ Fragment หรือกราฟการนำทางหากใช้
ไลบรารีการนำทาง
เช่น หากโฮสต์ Composable ในกิจกรรม viewModel()
always
จะแสดงอินสแตนซ์เดียวกันเสมอ ซึ่งจะล้างเมื่อกิจกรรมเสร็จสิ้นเท่านั้น
ในตัวอย่างต่อไปนี้ ผู้ใช้คนเดียวกัน ("user1") จะได้รับการต้อนรับ 2 ครั้งเนื่องจาก
มีการนำอินสแตนซ์ 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") ?: "") } } }
แหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว
เมื่อใช้ Compose ในส่วนหนึ่งของ UI ก็เป็นไปได้ที่ Compose และโค้ดระบบ View จะต้องแชร์ข้อมูล เราขอแนะนำให้คุณ
ห่อหุ้มสถานะที่แชร์นั้นไว้ในอีกคลาสหนึ่งที่ทำตามแนวทางปฏิบัติแนะนำของ UDF
ซึ่งทั้ง 2 แพลตฟอร์มใช้ เช่น ใน ViewModel
ที่แสดงสตรีมของ
ข้อมูลที่แชร์เพื่อส่งการอัปเดตข้อมูล
อย่างไรก็ตาม การดำเนินการดังกล่าวอาจเป็นไปไม่ได้เสมอไปหากข้อมูลที่จะแชร์มีการเปลี่ยนแปลงได้หรือเชื่อมโยงกับองค์ประกอบ UI อย่างใกล้ชิด ในกรณีดังกล่าว ระบบหนึ่งต้องเป็นแหล่งข้อมูลที่เชื่อถือได้ และระบบนั้นต้องแชร์การอัปเดตข้อมูลกับอีกระบบหนึ่ง โดยทั่วไปแล้ว แหล่งข้อมูลที่เชื่อถือได้ควรเป็นขององค์ประกอบที่อยู่ใกล้กับรูทของลำดับชั้น UI มากที่สุด
Compose เป็นแหล่งข้อมูลที่ถูกต้องเพียงแหล่งเดียว
ใช้
SideEffect
ที่ประกอบได้เพื่อเผยแพร่สถานะ Compose ไปยังโค้ดที่ไม่ใช่ Compose ในกรณีนี้ เราจะเก็บ
แหล่งข้อมูลที่เชื่อถือได้ไว้ใน Composable ซึ่งจะส่งการอัปเดตสถานะ
ตัวอย่างเช่น ไลบรารีการวิเคราะห์อาจช่วยให้คุณแบ่งกลุ่มประชากรผู้ใช้ได้โดยการแนบข้อมูลเมตาที่กำหนดเอง (พร็อพเพอร์ตี้ผู้ใช้ในตัวอย่างนี้) เข้ากับเหตุการณ์การวิเคราะห์ทั้งหมดที่ตามมา หากต้องการสื่อสารประเภทผู้ใช้ของ
ผู้ใช้ปัจจุบันไปยังไลบรารีการวิเคราะห์ ให้ใช้ 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
เพื่อให้ Compose ทำงานได้อย่างปลอดภัยในหลายเธรด หากใช้วิธีนี้ ฟังก์ชันที่ประกอบได้จะง่ายขึ้นเนื่องจาก
ไม่มีแหล่งข้อมูลความจริงอีกต่อไป แต่ระบบ View ต้องอัปเดต
สถานะที่เปลี่ยนแปลงได้และ View ที่ใช้สถานะนั้น
ในตัวอย่างต่อไปนี้ 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
ที่กำหนดเอง คุณอาจต้องใช้ทั้งในหน้าจอที่อิงตาม Compose และ View
ใน Compose องค์ประกอบ UI ที่แชร์จะกลายเป็น Composable ที่นำกลับมาใช้ใหม่ได้ทั่วทั้งแอป
ไม่ว่าองค์ประกอบนั้นจะได้รับการจัดรูปแบบโดยใช้ XML หรือเป็นมุมมองที่กำหนดเองก็ตาม
เช่น คุณจะสร้าง CallToActionButton
Composable สำหรับคอมโพเนนต์ข้อความกระตุ้นให้ดำเนินการ (Call-To-Action) ที่กำหนดเองButton
หากต้องการใช้ Composable ในหน้าจอที่อิงตาม View ให้สร้าง View Wrapper ที่กำหนดเองซึ่ง
ขยายจาก AbstractComposeView
ใน Content
Composable ที่ลบล้าง
ให้วาง 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 ช่วยให้แสดง Composable ที่แตกต่างกันโดยสิ้นเชิงได้ง่ายๆ โดยใช้ตรรกะแบบมีเงื่อนไขใน Kotlin ดังนี้
@Composable fun MyComposable(showCautionIcon: Boolean) { if (showCautionIcon) { CautionIcon(/* ... */) } }
CautionIcon
ไม่จำเป็นต้องทราบหรือสนใจว่าเหตุใดจึงมีการแสดงผล
และไม่มีแนวคิดของ visibility
: โดยจะอยู่ในองค์ประกอบหรือไม่อยู่
ก็ได้
การแยกการจัดการสถานะและตรรกะการนำเสนออย่างชัดเจนช่วยให้คุณเปลี่ยนวิธีแสดงเนื้อหาเป็น Conversion ของสถานะเป็น UI ได้อย่างอิสระมากขึ้น การยกสถานะขึ้นเมื่อจำเป็นยังช่วยให้ Composable นำกลับมาใช้ซ้ำได้มากขึ้น เนื่องจากความเป็นเจ้าของสถานะมีความยืดหยุ่นมากขึ้น
โปรโมตคอมโพเนนต์ที่แคปซูลและนำกลับมาใช้ใหม่ได้
องค์ประกอบ View
มักจะมีแนวคิดเกี่ยวกับตำแหน่งขององค์ประกอบนั้นๆ เช่น ภายใน Activity
, Dialog
, Fragment
หรือที่ใดที่หนึ่งภายในลำดับชั้น View
อื่น เนื่องจากมักจะขยายจากไฟล์เลย์เอาต์แบบคงที่ โครงสร้างโดยรวมของ View
จึงมักจะมีความยืดหยุ่นน้อยมาก ซึ่งจะส่งผลให้มีการเชื่อมโยงที่แน่นแฟ้นยิ่งขึ้น และทำให้View
เปลี่ยนแปลงหรือนำกลับมาใช้ใหม่ได้ยากขึ้น
ตัวอย่างเช่น View
ที่กำหนดเองอาจถือว่ามีมุมมองย่อยของ
ประเภทหนึ่งๆ ที่มีรหัสหนึ่งๆ และเปลี่ยนพร็อพเพอร์ตี้โดยตรงเพื่อตอบสนองต่อการดำเนินการบางอย่าง
ซึ่งจะเชื่อมโยงองค์ประกอบ View
เหล่านั้นเข้าด้วยกันอย่างแน่นแฟ้น กล่าวคือ View
ที่กำหนดเองอาจขัดข้องหรือใช้งานไม่ได้หากไม่พบองค์ประกอบย่อย และองค์ประกอบย่อยมักจะนำกลับมาใช้ใหม่ไม่ได้หากไม่มีองค์ประกอบหลัก View
ที่กำหนดเอง
ปัญหานี้จะลดลงใน Compose เมื่อใช้ Composable ที่นำกลับมาใช้ใหม่ได้ ผู้ปกครองสามารถ ระบุสถานะและฟังก์ชันเรียกกลับได้อย่างง่ายดาย คุณจึงเขียน 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
อาจแสดงได้หลายวิธี และControlPanelWithToggle
ไม่จำเป็นต้องเปลี่ยนแปลงสำหรับองค์ประกอบระดับบนสุด ไม่ว่า
ImageWithEnabledOverlay
หรือControlPanelWithToggle
จะซ้อนกันลึกแค่ไหนก็ตาม เด็กๆ อาจเคลื่อนไหวการเปลี่ยนแปลง สลับเนื้อหา หรือส่งต่อเนื้อหาให้เด็กคนอื่นๆ
รูปแบบนี้เรียกว่าการผกผันของการควบคุม ซึ่งคุณสามารถอ่านข้อมูลเพิ่มเติมได้ในCompositionLocal
เอกสารประกอบ
การจัดการการเปลี่ยนแปลงขนาดหน้าจอ
การมีแหล่งข้อมูลที่แตกต่างกันสำหรับขนาดหน้าต่างที่แตกต่างกันเป็นวิธีหลักวิธีหนึ่งในการ
สร้างView
เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ แม้ว่าทรัพยากรที่มีคุณสมบัติเหมาะสมจะยังคงเป็นตัวเลือก
สำหรับการตัดสินใจเกี่ยวกับเลย์เอาต์ระดับหน้าจอ แต่ Compose ก็ช่วยให้การเปลี่ยน
เลย์เอาต์ทั้งหมดในโค้ดด้วยตรรกะแบบมีเงื่อนไขปกติเป็นเรื่องง่ายขึ้นมาก ดูข้อมูลเพิ่มเติมได้ที่ใช้คลาสขนาดหน้าต่าง
นอกจากนี้ โปรดดูรองรับขนาดการแสดงผลต่างๆ เพื่อดูข้อมูลเกี่ยวกับเทคนิคที่ Compose มีให้ในการสร้าง UI แบบปรับเปลี่ยนได้
การเลื่อนที่ฝังไว้ด้วย View
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเปิดใช้การทำงานร่วมกันของการเลื่อนที่ซ้อนกันระหว่าง องค์ประกอบ View ที่เลื่อนได้และ Composable ที่เลื่อนได้ ซึ่งซ้อนกันทั้ง 2 ทิศทาง ได้ที่การทำงานร่วมกันของการเลื่อนที่ซ้อนกัน
เขียนใน RecyclerView
Composable ใน RecyclerView
มีประสิทธิภาพตั้งแต่ RecyclerView
เวอร์ชัน
1.3.0-alpha02 ตรวจสอบว่าคุณใช้
RecyclerView
เวอร์ชัน 1.3.0-alpha02 เป็นอย่างน้อยเพื่อดูสิทธิประโยชน์เหล่านั้น
WindowInsets
การทำงานร่วมกันกับ Views
คุณอาจต้องลบล้างระยะขอบเริ่มต้นเมื่อหน้าจอมีทั้ง View และโค้ด Compose ในลำดับชั้นเดียวกัน ในกรณีนี้ คุณต้องระบุอย่างชัดเจนว่า เลย์เอาต์ใดควรใช้ระยะขอบ และเลย์เอาต์ใดควรละเว้น
เช่น หากเลย์เอาต์ชั้นนอกสุดเป็นเลย์เอาต์ Android View คุณควร
ใช้ Inset ในระบบ View และไม่สนใจ Inset สำหรับ Compose
หรือหากเลย์เอาต์ชั้นนอกสุดเป็น Composable คุณควรใช้
ระยะขอบใน Compose และเว้นที่ว่างสำหรับ Composable AndroidView
ตามนั้น
โดยค่าเริ่มต้น ComposeView
แต่ละรายการจะใช้ขอบทั้งหมดที่ระดับการใช้งาน WindowInsetsCompat
หากต้องการเปลี่ยนลักษณะการทำงานเริ่มต้นนี้ ให้ตั้งค่า
ComposeView.consumeWindowInsets
เป็น false
อ่านข้อมูลเพิ่มเติมได้ในเอกสารประกอบเรื่อง WindowInsets
ใน Compose
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- แสดงอีโมจิ
- Material Design 2 ใน Compose
- ส่วนที่เว้นไว้ในหน้าต่างในโหมดเขียน