您可以在 Compose UI 中加入 Android 檢視區塊階層。如要使用 Compose 尚未提供的 UI 元素 (例如 AdView),這種做法就特別實用。您也可以透過這種做法重複使用自己設計的自訂檢視畫面。
如要加入檢視表元素或階層,請使用 AndroidView
可組合函式。AndroidView 會傳遞一個傳回 View 的 lambda。AndroidView 也提供了 update回呼,當 view 加載時呼叫的回呼。AndroidView 會在每次回呼變更時,讀取 State 時重組。舉例來說,如同其他內建可組合項,AndroidView 會透過可用的 Modifier 參數設定其本身在上層可組合項中的位置。
@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 版面配置,請使用 androidx.compose.ui:ui-viewbinding 程式庫提供的 AndroidViewBinding API。如要這麼做,您的專案必須啟用檢視畫面繫結。
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
Lazy 清單中的 AndroidView
如果您在 Lazy 清單 (LazyColumn、LazyRow、Pager 等) 中使用 AndroidView,建議您使用 1.4.0-rc01 版中推出的 AndroidView 超載。這個超載可讓 Compose 在重複使用包含的組合時,重複使用基礎 View 執行個體,就像 Lazy 清單一樣。
這個 AndroidView 超載會新增 2 個額外參數:
onReset:叫用回呼,表示即將重複使用View。這項屬性不得為空值,才能啟用 View 重複使用功能。onRelease(選用) - 叫用回呼,表示View已退出組合,不會再次重複使用。
@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() } ) } } }
Compose 中的片段 (過渡步驟)
使用 AndroidFragment 可組合項在 Compose 中新增 Fragment。AndroidFragment 採用片段特定處理方式,例如,在可組合項離開組合時移除片段。
如要加入片段,請使用 AndroidFragment 可組合函式。您將 Fragment 類別傳遞至 AndroidFragment,後者會直接將該類別的例項新增至組合結構。AndroidFragment 也提供 fragmentState 物件,用於建立具有指定狀態的 AndroidFragment、傳遞至新片段的 arguments,以及提供組合中片段的 onUpdate 回呼。如同其他內建可組合項,AndroidFragment 接受 Modifier 參數,可用於設定其本身在上層可組合項中的位置。
在 Compose 中呼叫 AndroidFragment,如下所示:
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
限制片段生命週期狀態
在 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 */ } }
從 Compose 呼叫 Android 架構
Compose 會在 Android 架構類別內運作。舉例來說,它託管於 Android View 類別 (例如 Activity 或 Fragment),並可能使用 Context 之類的 Android 架構類別、系統資源、Service 或 BroadcastReceiver。
如要進一步瞭解系統資源,請參閱「Compose 中的資源」。
Composition Locals
CompositionLocal 類別可讓使用者透過可編輯的函式以默示方式傳送資料。通常在 UI 樹狀結構的特定節點中提供值。該值可用在可撰寫的子系中,但不必將 CompositionLocal 宣告為可組合項中的參數。
CompositionLocal 的用途是在 Compose 中傳遞 Context、Configuration 或 View 等 Android 架構類型的值,其中的 Compose 程式碼是由對應的 LocalContext,LocalConfiguration,或 LocalView 所代管。請注意,CompositionLocal 類別前面會加上 Local,以在 IDE 中使用自動完成功能來進一步發現。
使用 current 屬性存取 CompositionLocal 目前的值。舉例來說,以下程式碼會在 Toast.makeToast 方法中提供 LocalContext.current,以顯示浮動式訊息。
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
廣播接收器
如要展示 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,請參閱這篇文章。舉例來說,這個合成事件會啟動其他活動:
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) } }