目录1.前言2.Android传统View调用Compose2.1新建传统View体系的Android项目2.2项目添加Compose配置2.2.1在android代码块添加2.2.2在d...
目录
1. 前言2. android传统View调用Compose
2.1 新建传统View体系的Android项目
2.2 项目添加Compose配置
2.2.1 在android代码块添加
2.2.2 在dependencies中添加依赖
2.3 定义Compose函数
2.4 修改XML文件
2.5 关联Compose函数
2.6 运行项目
3. Compose中调用Android View
3.1 调用传统View的日历
3.1.1 使用AndroidView
3.1.2 显示效果如下
3.2 调用传统View的WebView
3.2.1 添加网络权限
3.2.2 首先要注册WebView的生命周期
3.2.3 创建有状态的WebView
3.2.4 调用Android View
3.2.5 显示效果如下所示
4. 双层嵌套
4.1 在定义Xml中定义ComposeView
4.2 关联Compose函数
4.3 创建ids.xml定义原生view id
4.4 实现ComposeContent
4.5 在外层的原生代码处获取Compose中的原生View
4.6 运行项目
5. 本文源码下载
1. 前言
Compose 具有超强的兼容性,兼容现有的所有代码,Compose 能够与现有 View 体系并存,可实现渐进式替换。这就很有意义了,我们可以在现有项目中一小块一小块逐步地替换Compose,或者在旧项目中实现新的需求的时候,使用Compose。
今天,我们就来演示一下,Compose和Android View怎么互相调用,以及在双层嵌套(原生View嵌套Compose,Compose中又嵌套原生View)的情况下,在最外层原生View中,怎么获取到Compose内部的原生View。
2. Android传统View调用Compose
2.1 新建传统View体系的Android项目
新建项目的时候选择 Empty Activity

2.2 项目添加Compose配置
2.2.1 在android代码块添加
在app的build.config android代码块中添加
buildFeatures {
compose true
}
composeoptions {
kotlinCompilerExtensionVersion '1.1.1'
}
2.2.2 在dependencies中添加依赖
在app的build.config dependencies代码块中添加
dependencies {
//...省略...def compose_ui_version = '1.1.1'
implementation "androidx.compose.ui:ui:$compose_ui_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"implementation 'androidx.activity:activity-compose:1.3.1' //kotlin对应版本1.6.20
implementation 'androidx.compose.material:material:1.1.1'
}
2.3 定义Compose函数
在MainActivity.kt中定义Compose函数
@Composable
fun ComposeContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Hello world!")
}
}
2.4 修改xml文件
在activity_main.xml中添加androidx.compose.ui.platform.ComposeView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
2.5 关联Compose函数
在MainActivity.kt中,先通过findViewById找到ComposeView,然后通过composeView.setContent将Android 传统View和Compose建立关联。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val composeView : ComposeView = findViewById(R.id.compose_view)
composeView.setContent {
ComposeContent()
}
}
2.6 运行项目
可以发现界面显示如下,成功在传统View项目中调用了Compose了

3. Compose中调用Android View
3.1 调用传统View的日历
3.1.1 使用AndroidView
在@Composable内使用: androidx.compose.ui.viewinterop.AndroidView,然后在factory里面返回原生View即可
@Composable
fun AndroidViewpage() {
AndroidView(factory = {
CalendarView(it)
}, modifier = Modifier.fillMaxWidth(), update = {
it.setOnDateChangeListener { view, year, month, day ->
Toast.makeText(view.context, "${year}年${month}月${day}日", Toast.LENGTH_SHORT).show()
}
})
}
3.1.2 显示效果如下

3.2 调用传统View的WebView
3.2.1 添加网络权限
首先需要在AndroidManifest.xml中添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
3.2.2 首先要注册WebView的生命周期
@Composable
private fun rememberWebViewLifecycleObserver(webView: WebView): LifecycleEventObserver {
return remember(webView) {
LifecycleEventObserver { _, event ->
run {
when (event) {
Lifecycle.Event.ON_RESUME -> webView.onResume()
Lifecycle.Event.ON_PAUSE -> webView.onPause()
Lifecycle.Event.ON_DESTROY -> webView.destroy()
else -> Log.e("WebView", event.name)
}
}
}
}
}
3.2.3 创建有状态的WebView
创建有状态的WebView,并注册生命周期
@Composable
fun rememberWebViewWIthLifecycle(): WebView {
val context = LocalContext.current
val webView = remember {
WebView(context)
}
val lifecycleObserver = rememberWebViewLifecycleObserver(webView)
val lifecycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifecycle) {
lifecycle.addObserver(lifecycleObserver)
onDispose {
lifecycle.removeObserver(lifecycleObserver)
}
}
return webView
}
3.2.4 调用Android View
@Composable
fun WebViewPage() {
//创建有状态的WebView,并注册生命周期
val webView = rememberWebViewWIthLifecycle()
AndroidView(factory = {
webView
}, modifier = Modifier
.fillMaxSize() //宽高占满父布局
.background(Color.Red),
update = {webView ->
//设置支持JavaScript
val webSettings = webView.settings
webSettings.javascriptEnabled = true
webView.loadUrl("https://www.baidu.com")
})
}
3.2.5 显示效果如下所示

4. 双层嵌套
获取AndroidView中的原生View id
有时候,我们会遇到这种情况,就是在原生项目了,页面中有部分使用了Compose,然后在Compose中又有部分组件使用了原生View,这种情况下,要如何取到AndroidView中的原生View id 呢 ?
4.1 在定义Xml中定义ComposeView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
4.2 关联Compose函数
在MainActivity.kt中,先通过findViewById找到ComposeView,然后通过composeView.setContent将Android 传统View和Compose建立关联。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val composeView : ComposeView = findViewById(R.id.compose_view)
composeView.setContent {
ComposeContent()
}
}
@Composable
fun ComposeContent() {
//....
}
4.3 创建ids.xml定义原生view id
在resources/values目录下创建ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="my_calendar_view" />
</resources>
4.4 实现ComposeContent
@Composable
fun ComposeContent() {
AndroidView(factory = {
//这里也可以通过 layoutInflater.inflate(R.layout.xxxxxx) 的方式返回原生View
val calendarView = CalendarView(it)
val keyboard = R.id.my_calendar_view
Log.i(TAG,"my_calendar_view id:$keyboard")
calendarView.id = keyboard
calendarView
}, modifier = Modifier.fillMaxWidth(), update = {
it.setOnDateChangeListener { view, year, month, day ->
Toast.makeText(view.context, "${year}年${month}月${day}日", Toast.LENGTH_SHORT).show()
}
})
}
4.5 在外层的原生代码处获取Compose中的原生View
在原生代码的地方,通过composeView.findViewById查找id为my_calendar_view的原生View
window?.decorView?.post {
val calendarViewId = R.id.my_calendar_view
Log.i(TAG,"my_calendar_view id ===>:$calendarViewId")
val calendarView = composeView.findViewById<CalendarView>(calendarViewId)
Log.i(TAG,"calendarView:$calendarView")
calendarView.setOnDateChangeListener { view, year, month, day ->
Toast.makeText(view.context, "!!!! ${year}年${month}月${day}日", Toast.LENGTH_SHORT).show()
}
}
注意这里的window?.decorView?.post : 必须在页面加载完成后,才能查找到my_calendar_view对应的原生View,如果直接在onCreate里面去查找,会发现composeView.findViewById<CalendarView>(calendarViewId)返回的是null
4.6 运行项目
选择任意一个日期,可以发现弹出的toast是!!!! year年month月day日,即原生的setOnDateChangeListener覆盖了Compose中的setOnDateChangeListener监听,这样说明我们也在原生代码处,取到了Compose内部的原生View了。
5. 本文源码下载
本文源码下载地址 : 传送门
到此这篇关于Android View与Compose互相调用实例探究的文章就介绍到这了,更多相关Android View与Compose 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!










