Android View與Compose互相調(diào)用實(shí)例探究
1. 前言
Compose
具有超強(qiáng)的兼容性,兼容現(xiàn)有的所有代碼,Compose
能夠與現(xiàn)有 View
體系并存,可實(shí)現(xiàn)漸進(jìn)式替換。這就很有意義了,我們可以在現(xiàn)有項(xiàng)目中一小塊一小塊逐步地替換Compose
,或者在舊項(xiàng)目中實(shí)現(xiàn)新的需求的時(shí)候,使用Compose
。
今天,我們就來演示一下,Compose
和Android View
怎么互相調(diào)用,以及在雙層嵌套(原生View
嵌套Compose
,Compose
中又嵌套原生View
)的情況下,在最外層原生View
中,怎么獲取到Compose
內(nèi)部的原生View
。
2. Android傳統(tǒng)View調(diào)用Compose
2.1 新建傳統(tǒng)View體系的Android項(xiàng)目
新建項(xiàng)目的時(shí)候選擇 Empty Activity
2.2 項(xiàng)目添加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對(duì)應(yīng)版本1.6.20
implementation 'androidx.compose.material:material:1.1.1'
}
2.3 定義Compose函數(shù)
在MainActivity.kt
中定義Compose
函數(shù)
@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 關(guān)聯(lián)Compose函數(shù)
在MainActivity.kt
中,先通過findViewById
找到ComposeView
,然后通過composeView.setContent
將Android 傳統(tǒng)View和Compose
建立關(guān)聯(lián)。
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 運(yùn)行項(xiàng)目
可以發(fā)現(xiàn)界面顯示如下,成功在傳統(tǒng)View項(xiàng)目中調(diào)用了Compose
了
3. Compose中調(diào)用Android View
3.1 調(diào)用傳統(tǒng)View的日歷
3.1.1 使用AndroidView
在@Composable
內(nèi)使用: 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 調(diào)用傳統(tǒng)View的WebView
3.2.1 添加網(wǎng)絡(luò)權(quán)限
首先需要在AndroidManifest.xml
中添加網(wǎng)絡(luò)權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
3.2.2 首先要注冊(cè)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 創(chuàng)建有狀態(tài)的WebView
創(chuàng)建有狀態(tài)的WebView
,并注冊(cè)生命周期
@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 調(diào)用Android View
@Composable fun WebViewPage() { //創(chuàng)建有狀態(tài)的WebView,并注冊(cè)生命周期 val webView = rememberWebViewWIthLifecycle() AndroidView(factory = { webView }, modifier = Modifier .fillMaxSize() //寬高占滿父布局 .background(Color.Red), update = {webView -> //設(shè)置支持JavaScript val webSettings = webView.settings webSettings.javaScriptEnabled = true webView.loadUrl("https://www.baidu.com") }) }
3.2.5 顯示效果如下所示
4. 雙層嵌套
獲取AndroidView中的原生View id
有時(shí)候,我們會(huì)遇到這種情況,就是在原生項(xiàng)目了,頁面中有部分使用了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 關(guān)聯(lián)Compose函數(shù)
在MainActivity.kt
中,先通過findViewById
找到ComposeView
,然后通過composeView.setContent
將Android 傳統(tǒng)View和Compose
建立關(guān)聯(lián)。
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 創(chuàng)建ids.xml定義原生view id
在resources/values
目錄下創(chuàng)建ids.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <item type="id" name="my_calendar_view" /> </resources>
4.4 實(shí)現(xiàn)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
對(duì)應(yīng)的原生View,如果直接在onCreate里面去查找,會(huì)發(fā)現(xiàn)composeView.findViewById<CalendarView>(calendarViewId)
返回的是null
4.6 運(yùn)行項(xiàng)目
選擇任意一個(gè)日期,可以發(fā)現(xiàn)彈出的toast是!!!! year年month月day日
,即原生的setOnDateChangeListener
覆蓋了Compose
中的setOnDateChangeListener
監(jiān)聽,這樣說明我們也在原生代碼處,取到了Compose
內(nèi)部的原生View了。
5. 本文源碼下載
本文源碼下載地址 : 傳送門
到此這篇關(guān)于Android View與Compose互相調(diào)用實(shí)例探究的文章就介紹到這了,更多相關(guān)Android View與Compose 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android之Intent附加數(shù)據(jù)的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android之Intent附加數(shù)據(jù)的兩種實(shí)現(xiàn)方法,以實(shí)例形式較為詳細(xì)的分析了添加數(shù)據(jù)到Intent的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09ScrollView嵌套ListView滑動(dòng)沖突的解決方法
這篇文章主要介紹了ScrollView嵌套ListView滑動(dòng)沖突的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android CardView詳解及使用方法和實(shí)例
這篇文章主要介紹了Android CardView詳解及使用方法和實(shí)例的相關(guān)資料,這里附有實(shí)例代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-12-12Android自定義TextBanner實(shí)現(xiàn)自動(dòng)滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android自定義TextBanner實(shí)現(xiàn)自動(dòng)滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07Android編程操作聯(lián)系人的方法(查詢,獲取,添加等)
這篇文章主要介紹了Android編程操作聯(lián)系人的方法,包括針對(duì)聯(lián)系人的查詢,獲取,添加等操作,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-01-01Android ActionBar制作時(shí)鐘實(shí)例解析
這篇文章主要為大家詳細(xì)介紹了Android ActionBar制作時(shí)鐘的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05Android開發(fā)中button按鈕的使用及動(dòng)態(tài)添加組件方法示例
這篇文章主要介紹了Android開發(fā)中button按鈕的使用及動(dòng)態(tài)添加組件方法,涉及Android針對(duì)button按鈕的事件響應(yīng)及TextView動(dòng)態(tài)添加相關(guān)操作技巧,需要的朋友可以參考下2017-11-11