您可以在 Compose 界面中添加 Android View 层次结构。如果您要使用 Compose 中尚未提供的界面元素(如 AdView
),此方法特别有用。此方法还可让您重复使用您可能已设计的自定义视图。
如需添加视图元素或层次结构,请使用 AndroidView
可组合项。系统会向 AndroidView
传递一个返回 View
的 lambda。AndroidView
还提供了在视图膨胀时被调用的 update
回调。每当在该回调中读取的 State
发生变化时,AndroidView
都会重组。与许多其他内置可组合项一样,AndroidView
接受 Modifier
参数,该参数可用于设置它在父级可组合项中的位置等用途。
@Composable fun CustomView() { var selectedItem by remember { mutableStateOf(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) } }
延迟列表中的 AndroidView
如果您在延迟列表(LazyColumn
、LazyRow
、Pager
等)中使用 AndroidView
,请考虑使用版本 1.4.0-rc01 中引入的 AndroidView
重载。通过此重载,当包含的组合被重复使用时,Compose 可以重复使用底层 View
实例,就像延迟列表一样。
AndroidView
的此重载会添加 2 个额外的参数:
onReset
- 调用的回调,用于指示View
即将被重复使用。此值必须不为 null,才能实现 View 重用。onRelease
(可选)- 调用的回调,用于指示View
已退出组合,且不会再次重复使用。
@OptIn(ExperimentalComposeUiApi::class) @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 中的 fragment
使用 AndroidViewBinding
可组合项在 Compose 中添加 Fragment
。AndroidViewBinding
包含特定于 fragment 的处理方式,例如当可组合项退出组合时移除 fragment。
为此,请将包含 FragmentContainerView
作为您 Fragment
容器的 XML 膨胀。
例如,如果您已定义 my_fragment_layout.xml
,那么在将 android:name
XML 属性替换为 Fragment
的类名称时,您可以使用如下代码:
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container_view" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.example.compose.snippets.interop.MyFragment" />
在 Compose 中膨胀此 fragment,如下所示:
@Composable fun FragmentInComposeExample() { AndroidViewBinding(MyFragmentLayoutBinding::inflate) { val myFragment = fragmentContainerView.getFragment<MyFragment>() // ... } }
如果您需要在同一布局中使用多个 fragment,请确保您已为每个 FragmentContainerView
定义唯一 ID。
从 Compose 调用 Android 框架
Compose 在 Android 框架类中运行。例如,它托管在 Android View 类(如 Activity
或 Fragment
)上,并且可能会使用 Android 框架类(如 Context
、系统资源、Service
或 BroadcastReceiver
)。
如需详细了解系统资源,请参阅 Compose 中的资源。
CompositionLocal
CompositionLocal
类允许通过可组合函数隐式传递数据。它们通常在界面树的某个节点具有一个值。该值可供其可组合项的后代使用,而无需在可组合函数中将 CompositionLocal
声明为参数。
CompositionLocal
用于为 Compose 中的 Android 框架类型(例如 Context
、Configuration
或 View
)传播值,其中 Compose 代码与相应的 LocalContext
、LocalConfiguration
或 LocalView
一起托管。请注意,CompositionLocal
类的前缀是 Local
,以便于 IDE 中的自动补全功能更轻松地检测到这些类。
CompositionLocal
的当前值可通过它的 current
属性进行访问。例如,以下代码通过向 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") } }
如需查看更完整的示例,请参阅本文档末尾的案例研究:BroadcastReceiver 部分。
其他交互
如果没有为您需要的交互定义实用程序,最佳实践是遵循常规 Compose 准则,即数据向下流动而事件向上流动(Compose 编程思想一文对此进行了更为详细的说明)。例如,以下可组合函数会启动一个不同的 activity:
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) } }
案例研究:BroadcastReceiver
举一个更实际的例子,您可能想要迁移一些功能或在 Compose 中实现一些功能,以及展示 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 */ }
后续步骤
现在,您已经了解在 View 中使用 Compose 以及在 Compose 中使用 View 时的互操作性 API。如需了解更多内容,可以浏览其他注意事项页面。
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 其他注意事项
- Compose 中的附带效应
- 使用 CompositionLocal 将数据的作用域限定在局部