您可以在 Compose UI 中包含 Android View 层次结构。如果您想使用 Compose 中尚不可用的 UI 元素(例如 AdView
),此方法特别有用。此方法还允许您重用可能已设计的自定义视图。
要包含视图元素或层次结构,请使用 AndroidView
可组合项。 AndroidView
被传递一个返回 View
的 lambda 表达式。 AndroidView
还提供了一个 update
回调函数,该函数在视图膨胀时被调用。 AndroidView
每当回调函数中读取的 State
发生变化时都会重新组合。 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 布局,请使用 AndroidViewBinding
API,该 API 由 androidx.compose.ui:ui-viewbinding
库提供。要执行此操作,您的项目必须启用 视图绑定。
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView
在 Lazy 列表中
如果您在 Lazy 列表(LazyColumn
、LazyRow
、Pager
等)中使用 AndroidView
,请考虑使用在版本 1.4.0-rc01 中引入的 AndroidView
重载。此重载允许 Compose 在包含的组合被重用时重用底层的 View
实例,就像 Lazy 列表一样。
此 AndroidView
重载添加了 2 个额外的参数
onReset
- 一个回调函数,用于指示View
即将被重用。为了启用 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 中的片段
使用 AndroidViewBinding
可组合项在 Compose 中添加 Fragment
。 AndroidViewBinding
具有特定于片段的处理,例如在可组合项离开组合时移除片段。
为此,请膨胀包含 FragmentContainerView
的 XML 作为您 Fragment
的容器。
例如,如果您已定义 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 中膨胀此片段,如下所示
@Composable fun FragmentInComposeExample() { AndroidViewBinding(MyFragmentLayoutBinding::inflate) { val myFragment = fragmentContainerView.getFragment<MyFragment>() // ... } }
如果您需要在同一个布局中使用多个片段,请确保为每个 FragmentContainerView
定义了唯一的 ID。
从 Compose 调用 Android 框架
Compose 在 Android 框架类中运行。例如,它托管在 Android View 类(例如 Activity
或 Fragment
)上,并且可能使用 Android 框架类,例如 Context
、系统资源、Service
或 BroadcastReceiver
。
要详细了解系统资源,请参阅 Compose 中的资源。
组合局部变量
CompositionLocal
类允许通过可组合函数隐式传递数据。它们通常在 UI 树的特定节点中提供值。该值可以由其可组合的子节点使用,而无需将 CompositionLocal
声明为可组合函数的参数。
CompositionLocal
用于在 Compose 中传播 Android 框架类型的值,例如 Context
、Configuration
或托管 Compose 代码的 View
,以及相应的 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") } }
有关更完整的示例,请查看本文档末尾的 案例研究:广播接收器 部分。
其他交互
如果没有为所需的交互定义实用程序,最佳做法是遵循通用的 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) } }
案例研究:广播接收器
为了更切合实际地说明您可能想要迁移或在 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 或反之亦然的互操作性 API,请浏览 其他注意事项 页面以了解更多信息。
为您推荐
- 注意:当 JavaScript 关闭时显示链接文本
- 其他注意事项
- Compose 中的副作用
- 使用 CompositionLocal 进行局部作用域数据