<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Compose
具有超強的相容性,相容現有的所有程式碼,Compose
能夠與現有 View
體系並存,可實現漸進式替換。這就很有意義了,我們可以在現有專案中一小塊一小塊逐步地替換Compose
,或者在舊專案中實現新的需求的時候,使用Compose
。
今天,我們就來演示一下,Compose
和Android View
怎麼互相呼叫,以及在雙層巢狀(原生View
巢狀Compose
,Compose
中又巢狀原生View
)的情況下,在最外層原生View
中,怎麼獲取到Compose
內部的原生View
。
新建專案的時候選擇 Empty Activity
在app
的build.config
android
程式碼塊中新增
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.1.1'
}
在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'
}
在MainActivity.kt
中定義Compose
函數
@Composable fun ComposeContent() { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { Text(text = "Hello world!") } }
在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>
在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() } }
可以發現介面顯示如下,成功在傳統View專案中呼叫了Compose
了
在@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() } }) }
首先需要在AndroidManifest.xml
中新增網路許可權
<uses-permission android:name="android.permission.INTERNET" />
@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) } } } } }
建立有狀態的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 }
@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") }) }
獲取AndroidView中的原生View id
有時候,我們會遇到這種情況,就是在原生專案了,頁面中有部分使用了Compose,然後在Compose中又有部分元件使用了原生View,這種情況下,要如何取到AndroidView中的原生View id 呢 ?
<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>
在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() { //.... }
在resources/values
目錄下建立ids.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <item type="id" name="my_calendar_view" /> </resources>
@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() } }) }
在原生程式碼的地方,通過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
選擇任意一個日期,可以發現彈出的toast是!!!! year年month月day日
,即原生的setOnDateChangeListener
覆蓋了Compose
中的setOnDateChangeListener
監聽,這樣說明我們也在原生程式碼處,取到了Compose
內部的原生View了。
本文原始碼下載地址 : 傳送門
到此這篇關於Android View與Compose互相呼叫範例探究的文章就介紹到這了,更多相關Android View與Compose 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45