Compose和XML的代码互相调用

「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。

传统 xml 布局项目中使用 Compose 方法

就像第一次使用kt一样,很多项目都是java和kt混着用,在难以确保开发协同工作人员同等技术追求(比如有的人想用Compose、有的人不想)的情况下,这种情况极易发生。所以传统XML布局和Compose方法互相调用的场景发生了也很正常。

相应的,谷歌公司已经考虑到这种情况,Compose 工具包已经提供了 androidx.compose.ui.platform.ComposeView 供在XML文件中使用Compose。

比如一个空的Activity布局xml文件中,我们加入 androidx.compose.ui.platform.ComposeView 如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_xml"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView For XML"
        android:layout_gravity="center_horizontal"/>

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/tv_compose"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
复制代码

很常规的一段代码,只是Compose里的组件通过androidx.compose.ui.platform.ComposeView来声明,这个时候在activity里通过findViewById来获取实例:

val mTvCompose = findViewById<ComposeView>(R.id.tv_compose)
复制代码

注意这里的findViewById后是个再接的id。

这时候就可以把他当做在compose中组件来用了。

val mTvXml = findViewById<TextView>(R.id.tv_xml)
val mTvCompose = findViewById<ComposeView>(R.id.tv_compose)
mTvXml.text = "This is a TextView for XML"
mTvCompose.setContent {
    Column() {
        Text(text = "这是Compose组件")
        Text(text = "成功调用")
    }
}
复制代码

对应的显示效果为:

image.png

使用addView()来添加View对于ComposeView来说也同样可以,具体形式为:

setContentView(LinearLayout(this).apply {
    orientation = VERTICAL
    addView(ComposeView(this@MainActivity).apply {
        id = R.id.ll_layout
        setContent {
            MaterialTheme {
                Text("LinearLayout Compose View")
            }
        }
    })
    addView(TextView(context).apply {
        text = "TextView for xml"
    })
    addView(ComposeView(context).apply {
        id = R.id.tv_compose
        setContent {
            MaterialTheme {
                Text("ComposeView here")
            }
        }
    })
})
复制代码

Compose中使用View

唯物主义常说,事物往往都具有两面性,有在XML中想用Compose的情况,就会有在Compose中想用传统View的情况(比如想使用一些以前写好的自定义View、要用的View还没有Compose版本,,比如AdView, WebView之类的),同样Google也提供了 AndroidView 来实现这种操作。

例如以下代码:

setContent {
    AndroidView(factory = {
        TextView(it)
    }){
        it.apply {
            text = "这是Compose里引用原生的TextView"
        }
    }
}
复制代码

对应的效果为:

image.png

这时,我们看这个方法的构造函数:

@Composable
fun <T : View> AndroidView(
    factory: (Context) -> T,
    modifier: Modifier = Modifier,
    update: (T) -> Unit = NoOpUpdate
)
复制代码

不难看出,这里的factory接收一个Context参数, 用来构建一个View。Modifier是修饰符,这个之前我们详细讲解过,可以花式定义组件的函数。update()是一个callback,inflate之后会执行,读取的状态state值变化后也会被执行。

上述的代码是将TextView作为factory参数传入进去来构建一个View的。构建成功后会使用lamba调用后面{}内容(这句话可能没描述清楚)。

至此,算是成功在Compose中使用View了。啥,问我怎么在.java文件中调用Compose?不好意思,Compose只支持kotlin文件中调用。

Compose & View

从上述代码中,不难看出:

ComposeView其实是个Android的View。

AndroidView其实是个Compose函数。

AndroidView和ComposeView是采用传统XML的View和Compose组件互相调用的桥梁。

猜你喜欢

转载自juejin.im/post/7067472608127615006
今日推荐