คุณสามารถรวมลำดับชั้นการแสดงผลของ Android ไว้ใน Compose UI ได้ วิธีนี้มีประโยชน์อย่างยิ่งหากคุณต้องการใช้องค์ประกอบ UI ที่ยังไม่พร้อมใช้งานใน Compose เช่น AdView
วิธีนี้ยังช่วยให้คุณนำมุมมองที่กำหนดเองซึ่งคุณอาจออกแบบไว้กลับมาใช้ซ้ำได้ด้วย
หากต้องการรวมองค์ประกอบหรือลำดับชั้นของมุมมอง ให้ใช้ Composable AndroidView
AndroidView จะส่งผ่าน Lambda ที่แสดงผล View นอกจากนี้ AndroidView ยังมี Callback update ที่จะเรียกใช้เมื่อขยายมุมมอง AndroidView จะจัดองค์ประกอบใหม่เมื่อใดก็ตามที่มีการเปลี่ยนแปลง State ที่อ่านภายใน Callback AndroidView เช่นเดียวกับ Composable ในตัวอื่นๆ จะใช้พารามิเตอร์ Modifier ที่สามารถใช้เพื่อกำหนดตำแหน่งใน Composable หลัก เป็นต้น
@Composable fun CustomView() { var selectedItem by remember { mutableIntStateOf(0) } // Adds view to Compose AndroidView( modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree factory = { context -> // Creates view MyView(context).apply { // Sets up listeners for View -> Compose communication setOnClickListener { selectedItem = 1 } } }, update = { view -> // View's been inflated or state read in this block has been updated // Add logic here if necessary // As selectedItem is read here, AndroidView will recompose // whenever the state changes // Example of Compose -> View communication view.selectedItem = selectedItem } ) } @Composable fun ContentExample() { Column(Modifier.fillMaxSize()) { Text("Look at this CustomView!") CustomView() } }
AndroidView พร้อมการเชื่อมโยงมุมมอง
หากต้องการฝังเลย์เอาต์ XML ให้ใช้ API AndroidViewBinding ซึ่งไลบรารี androidx.compose.ui:ui-viewbinding มีให้ โดยโปรเจ็กต์ของคุณต้องเปิดใช้ view binding เพื่อดำเนินการนี้
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView ใน Lazy List
หากคุณใช้ AndroidView ใน Lazy list (LazyColumn, LazyRow, Pager ฯลฯ) ให้พิจารณาใช้โอเวอร์โหลด AndroidView ที่เปิดตัวในเวอร์ชัน 1.4.0-rc01 การโอเวอร์โหลดนี้ช่วยให้ Compose นำอินสแตนซ์ View ที่สำคัญกลับมาใช้ซ้ำได้เมื่อมีการนำคอมโพสิชันที่มีอยู่กลับมาใช้ซ้ำ เช่นเดียวกับกรณีของรายการแบบ Lazy
การโอเวอร์โหลด AndroidView นี้จะเพิ่มพารามิเตอร์อีก 2 รายการ ดังนี้
onReset- Callback ที่เรียกใช้เพื่อส่งสัญญาณว่ากำลังจะนำViewกลับมาใช้ซ้ำ ค่านี้ต้องไม่ใช่ค่า Null เพื่อเปิดใช้การนำมุมมองกลับมาใช้ซ้ำonRelease(ไม่บังคับ) - Callback ที่เรียกใช้เพื่อส่งสัญญาณว่าViewออกจาก Composition แล้วและจะไม่นำมาใช้ซ้ำอีก
@Composable fun AndroidViewInLazyList() { LazyColumn { items(100) { index -> AndroidView( modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree factory = { context -> MyView(context) }, update = { view -> view.selectedItem = index }, onReset = { view -> view.clear() } ) } } }
Fragment ใน Compose (ขั้นตอนการเปลี่ยนผ่าน)
ใช้ Composable AndroidFragment เพื่อเพิ่ม Fragment ใน Compose
AndroidFragment มีการจัดการเฉพาะ Fragment เช่น การนำ Fragment ออกเมื่อ Composable ออกจาก Composition
หากต้องการรวม Fragment ให้ใช้ AndroidFragment Composable คุณส่งคลาส Fragment ไปยัง AndroidFragment ซึ่งจะเพิ่มอินสแตนซ์ของคลาสนั้นลงในองค์ประกอบโดยตรง AndroidFragment ยังมีออบเจ็กต์ fragmentState เพื่อสร้าง AndroidFragment ด้วยสถานะที่ระบุ, arguments เพื่อส่งไปยัง Fragment ใหม่ และ Callback onUpdate ที่ให้ Fragment จาก Composition AndroidFragment จะยอมรับพารามิเตอร์ Modifier เช่นเดียวกับ Composable ในตัวอื่นๆ อีกหลายรายการ ซึ่งคุณสามารถใช้เพื่อกำหนดตำแหน่งใน Composable ระดับบนได้ เป็นต้น
เรียกใช้ AndroidFragment ใน Compose ดังนี้
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
จำกัดสถานะวงจรของ Fragment
ใน Fragment 1.9.0 ขึ้นไป คุณสามารถใช้พารามิเตอร์ maxLifecycle เพื่อจำกัดสถานะวงจรของ Fragment ที่ฝังไว้ได้
ตัวอย่างเช่น ใน HorizontalPager คุณสามารถตั้งค่า maxLifecycle เป็น RESUMED แบบไดนามิกได้เฉพาะเมื่อหน้าเว็บที่เกี่ยวข้องทำงานอยู่ โดยจำกัดหน้าเว็บที่อยู่นอกหน้าจอไว้ที่ STARTED เมื่อผู้ใช้ไปยังหน้าอื่น ขีดจำกัดส่วนย่อยของหน้าก่อนหน้าจะกลายเป็น STARTED ซึ่งจะหยุดชั่วคราวหรือยกเลิกภาระงานที่กำหนดขอบเขตไว้ที่ RESUMED (เช่น โครูทีนที่ทำงานใน repeatOnLifecycle(RESUMED)) เพื่อป้องกันไม่ให้หน้าเว็บที่อยู่นอกหน้าจอทำงานเฉพาะในเบื้องหน้าขณะที่ยังคงเริ่มต้น UI ไว้ที่ STARTED
HorizontalPager(state = pagerState) { page -> // Dynamically cap the lifecycle state based on whether the page is selected val maxLifecycle = if (pagerState.settledPage == page) { Lifecycle.State.RESUMED } else { Lifecycle.State.STARTED } when (page) { 0 -> AndroidFragment<HomeFragment>(maxLifecycle = maxLifecycle) 1 -> AndroidFragment<LibraryFragment>(maxLifecycle = maxLifecycle) /* Other pages and corresponding fragments */ } }
การเรียกใช้เฟรมเวิร์ก Android จาก Compose
Compose ทำงานภายในคลาสเฟรมเวิร์กของ Android เช่น โฮสต์อยู่ในคลาส Android View เช่น Activity หรือ Fragment และอาจใช้คลาสเฟรมเวิร์ก Android เช่น Context, ทรัพยากรระบบ, Service หรือ BroadcastReceiver
ดูข้อมูลเพิ่มเติมเกี่ยวกับทรัพยากรระบบได้ที่ทรัพยากรใน Compose
CompositionLocal
คลาส CompositionLocal ช่วยให้ส่งข้อมูลโดยนัยผ่านฟังก์ชันที่ประกอบกันได้ โดยปกติแล้วจะมีการระบุค่าในโหนดหนึ่งๆ ของโครงสร้าง UI ค่าดังกล่าวสามารถใช้โดยองค์ประกอบสืบทอดที่ประกอบกันได้โดยไม่ต้องประกาศ CompositionLocal เป็นพารามิเตอร์ในฟังก์ชันที่ประกอบกันได้
CompositionLocal ใช้เพื่อเผยแพร่ค่าสำหรับประเภทเฟรมเวิร์ก Android ใน Compose เช่น Context, Configuration หรือ View ที่โฮสต์โค้ด Compose ด้วย LocalContext, LocalConfiguration หรือ LocalView ที่เกี่ยวข้อง
โปรดทราบว่าคลาส CompositionLocal จะขึ้นต้นด้วย Local เพื่อให้ค้นพบได้ง่ายขึ้นด้วยการเติมข้อความอัตโนมัติใน IDE
เข้าถึงค่าปัจจุบันของ CompositionLocal โดยใช้พร็อพเพอร์ตี้ current ตัวอย่างเช่น โค้ดด้านล่างแสดงข้อความโทสต์โดยระบุ LocalContext.current ลงในเมธอด Toast.makeToast
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
Broadcast Receiver
เพื่อแสดง CompositionLocal และผลข้างเคียง หากต้องลงทะเบียน BroadcastReceiver จากฟังก์ชันที่ประกอบกันได้ ให้ใช้ LocalContext เพื่อใช้บริบทปัจจุบัน และผลข้างเคียง rememberUpdatedState และ DisposableEffect
@Composable fun SystemBroadcastReceiver( systemAction: String, onSystemEvent: (intent: Intent?) -> Unit ) { // Grab the current context in this part of the UI tree val context = LocalContext.current // Safely use the latest onSystemEvent lambda passed to the function val currentOnSystemEvent by rememberUpdatedState(onSystemEvent) // If either context or systemAction changes, unregister and register again DisposableEffect(context, systemAction) { val intentFilter = IntentFilter(systemAction) val broadcast = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { currentOnSystemEvent(intent) } } context.registerReceiver(broadcast, intentFilter) // When the effect leaves the Composition, remove the callback onDispose { context.unregisterReceiver(broadcast) } } } @Composable fun HomeScreen() { SystemBroadcastReceiver(Intent.ACTION_BATTERY_CHANGED) { batteryStatus -> val isCharging = /* Get from batteryStatus ... */ true /* Do something if the device is charging */ } /* Rest of the HomeScreen */ }
การโต้ตอบรูปแบบอื่น
หากไม่มีการกำหนดฟังก์ชันสำหรับปฏิสัมพันธ์ที่คุณต้องการ แนวทางปฏิบัติแนะนำคือให้ทำตามหลักเกณฑ์ทั่วไปของ Compose นั่นคือข้อมูลไหลลง เหตุการณ์ไหลขึ้น (ดูรายละเอียดเพิ่มเติมได้ในการคิดใน Compose) ตัวอย่างเช่น Composable นี้จะเปิดกิจกรรมอื่น
class OtherInteractionsActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // get data from savedInstanceState setContent { MaterialTheme { ExampleComposable(data, onButtonClick = { startActivity(Intent(this, MyActivity::class.java)) }) } } } } @Composable fun ExampleComposable(data: DataExample, onButtonClick: () -> Unit) { Button(onClick = onButtonClick) { Text(data.title) } }