4-和原生混用
互相调用
Interoperability API | Jetpack Compose | Android Developers
Jetpack Compose和View的互操作性 - 圣骑士wind - 博客园
Compose 和 View 的结合, 主要是靠两个桥梁.
还挺有趣的:
ComposeView其实是个 Android View.AndroidView其实是个 Composable 方法.
Compose 和 View 可以互相兼容的特点保证了项目可以逐步迁移, 并且也给够了安全感, 像极了当年 java 项目迁移 kotlin,至于什么学习曲线, 经验不足, 反正早晚都要学的, 整点新鲜的也挺好
混用方案概览
主要有两种混用方向:
在原生页面中使用 Compose(更常见)
在 Compose 页面中使用原生 View
一、在原生页面中使用 Compose(你的场景)
这是最常见的迁移路径:保持现有的 Activity/Fragment,只在部分区域使用 Compose。
核心 API:ComposeView
ComposeView 是一个 Android View,可以在 XML 布局或代码中使用,它内部可以承载 Compose UI。
方式 1:在 XML 布局中使用
XML 布局 (activity_main.xml):
1 | |
Activity 代码:
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 操作原生 View
findViewById<Button>(R.id.native_button).setOnClickListener {
Toast.makeText(this, "原生按钮点击", Toast.LENGTH_SHORT).show()
}
// 设置 Compose 内容
val composeView = findViewById<ComposeView>(R.id.compose_view)
composeView.setContent {
// 这里是 Compose 的世界
MyComposableContent("来自原生的参数")
}
}
}
@Composable
fun MyComposableContent(message: String) {
var count by remember { mutableStateOf(0) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "这是 Compose 组件")
Text(text = "消息: $message")
Text(text = "计数: $count")
Button(onClick = { count++ }) {
Text("Compose 按钮")
}
}
}
方式 2:在代码中动态添加
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val composeView = ComposeView(this).apply {
setContent {
MyComposableContent()
}
}
// 添加到现有的 ViewGroup 中
val root = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
addView(TextView(this@MainActivity).apply {
text = "原生 TextView"
})
addView(composeView)
}
setContentView(root)
}
}
通信:原生与 Compose 的数据传递
1. 原生 → Compose:通过参数传递
kotlin
// 在 Activity 中
var currentTheme = “Light”
composeView.setContent {
// 将原生数据作为参数传递给 Compose
MyComposableContent(theme = currentTheme)
}
// 改变主题
fun changeTheme(theme: String) {
currentTheme = theme
// 需要重新设置 Compose 内容或使用状态管理
composeView.setContent {
MyComposableContent(theme = currentTheme)
}
}
2. Compose → 原生:通过回调接口
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val composeView = findViewById<ComposeView>(R.id.compose_view)
composeView.setContent {
MyComposableContent(
onButtonClick = { message ->
// Compose 中发生的事件回调到原生
Toast.makeText(this, "Compose 说: $message", Toast.LENGTH_SHORT).show()
// 可以操作其他原生 View
findViewById<TextView>(R.id.title_text).text = "收到: $message"
}
)
}
}
}
@Composable
fun MyComposableContent(onButtonClick: (String) -> Unit) {
Button(onClick = {
onButtonClick(“Hello from Compose!”)
}) {
Text(“通知原生”)
}
}
二、在 Compose 中使用原生 View
核心 API:AndroidView
kotlin
@Composable
fun WebViewComposable(url: String) {
AndroidView(
factory = { context ->
// 创建原生 View
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
webViewClient = WebViewClient()
}
},
update = { webView ->
// 当参数变化时更新
webView.loadUrl(url)
}
)
}
// 使用
@Composable
fun MyScreen() {
Column {
Text(“这是 Compose 文本”)
WebViewComposable(“https://www.example.com“)
Button(onClick = { /* … */ }) {
Text(“Compose 按钮”)
}
}
}