这篇文章主要讲解了“Android View与Compose互相调用的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android View与Compose互相调用的方法是什么”吧!
1. 前言
Compose
具有超强的兼容性,兼容现有的所有代码,Compose
能够与现有 View
体系并存,可实现渐进式替换。这就很有意义了,我们可以在现有项目中一小块一小块逐步地替换Compose
,或者在旧项目中实现新的需求的时候,使用Compose
。
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
函数
@Composablefun 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() }}
3. Compose中调用Android View
3.1 调用传统View的日历
3.1.1 使用AndroidView
在@Composable
内使用: androidx.compose.ui.viewinterop.AndroidView
,然后在factory
里面返回原生View
即可
@Composablefun 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的生命周期
@Composableprivate 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
,并注册生命周期
@Composablefun 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
@Composablefun 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") })}
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() }}@Composablefun 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
@Composablefun 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了。
感谢各位的阅读,以上就是“Android View与Compose互相调用的方法是什么”的内容了,经过本文的学习后,相信大家对Android View与Compose互相调用的方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!