开发者

Android View与Compose互相调用实例探究

开发者 https://www.devze.com 2023-01-31 10:26 出处:网络 作者: 氦客
目录1. 前言2. android传统View调用Compose2.1 新建传统View体系的Android项目2.2 项目添加Compose配置2.2.1 在android代码块添加2.2.2 在dependencies中添加依赖2.3 定义Compose函数2.4 修改XML文件2.5 关联Compose
目录
  • 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

                        今天,我们就来演示一下,ComposeAndroid View怎么互相调用,以及在双层嵌套(原生View嵌套ComposeCompose中又嵌套原生View)的情况下,在最外层原生View中,怎么获取到Compose内部的原生View

                        2. Android传统View调用Compose

                        2.1 新建传统View体系的Android项目

                        新建项目的时候选择 Empty Activity

                        Android View与Compose互相调用实例探究

                        2.2 项目添加Compose配置

                        2.2.1 在android代码块添加

                        appbuild.config android代码块中添加

                        buildFeatures {

                            compose true

                        }

                        composeoptions {

                            kotlinCompilerExtensionVersion '1.1.1'

                        }

                        2.2.2 在dependencies中添加依赖

                        appbuild.config dependencies代码块中添加

                        dependencies {

                            //...省略...

                            def compo开发者_JS开发se_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(savedCwzCYUInstanceState)
                            setContentView(R.layout.activity_main)
                            val composeView : ComposeView = findViewById(R.id.compose_view)
                            composeView.setContent {
                                ComposeContent()
                            }
                        }
                        

                        2.6 运行项目

                        可以发现界面显示如下,成功在传统View项目中调用了Compose

                        Android 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 显示效果如下

                        Android View与Compose互相调用实例探究

                        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 = {
                        python        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 显示效果如下所示

                        Android View与Compose互相调用实例探究

                        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:la编程yout_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" naCwzCYUme="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 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

                        0

                        精彩评论

                        暂无评论...
                        验证码 换一张
                        取 消

                        关注公众号