您可以在 Compose 界面中包含 Android View 层次结构。如果您想使用 Compose 中尚不可用的界面元素(例如 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 布局,请使用 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
即将重用时发出的回调。要启用 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 中的自动完成功能更好地发现。
通过使用其 current
属性访问 CompositionLocal
的当前值。例如,下面的代码通过将 LocalContext.current
提供给 Toast.makeToast
方法来显示 Toast 消息。
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
有关更完整的示例,请参阅本文档末尾的案例研究:BroadcastReceivers 部分。
其他交互
如果您所需的交互没有定义实用程序,最佳实践是遵循通用 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) } }
案例研究:广播接收器
为了更真实地了解您可能希望在 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 的局部作用域数据