4-和原生混用

互相调用

Interoperability API  |  Jetpack Compose  |  Android Developers

Jetpack Compose和View的互操作性 - 圣骑士wind - 博客园

Compose 和 View 的结合, 主要是靠两个桥梁.
还挺有趣的:

  • ComposeView 其实是个 Android View.
  • AndroidView 其实是个 Composable 方法.

Compose 和 View 可以互相兼容的特点保证了项目可以逐步迁移, 并且也给够了安全感, 像极了当年 java 项目迁移 kotlin,至于什么学习曲线, 经验不足, 反正早晚都要学的, 整点新鲜的也挺好

混用方案概览

主要有两种混用方向:

  1. 在原生页面中使用 Compose(更常见)

  2. 在 Compose 页面中使用原生 View

一、在原生页面中使用 Compose(你的场景)

这是最常见的迁移路径:保持现有的 Activity/Fragment,只在部分区域使用 Compose。

核心 API:ComposeView

ComposeView 是一个 Android View,可以在 XML 布局或代码中使用,它内部可以承载 Compose UI。

方式 1:在 XML 布局中使用

XML 布局 (activity_main.xml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<!-- 传统的 TextView -->
<TextView
android:id="@+id/title_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是原生标题" />

<!-- 传统的 Button -->
<Button
android:id="@+id/native_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="原生按钮" />

<!-- Compose 区域 -->
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

</LinearLayout>

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 按钮”)
}
}
}


4-和原生混用
http://peiniwan.github.io/2025/12/7366689dcdfe.html
作者
六月的雨
发布于
2025年12月16日
许可协议