传统 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组件互相调用的桥梁。

GitHub 加速计划 / compose / compose
33.28 K
5.15 K
下载
compose - Docker Compose是一个用于定义和运行多容器Docker应用程序的工具,通过Compose文件格式简化应用部署过程。
最近提交(Master分支:3 个月前 )
5e3a0953 full diff: https://github.com/docker/cli/compare/v27.4.0-rc.1...8d1bacae3e49ed1d096eede8eef4ae851d7f2eae Signed-off-by: Sebastiaan van Stijn <github@gone.nl> 7 天前
a2a3eb72 - full diff: https://github.com/docker/cli/compare/cb3048fbebb1...v27.4.0-rc.1 Signed-off-by: Sebastiaan van Stijn <github@gone.nl> 7 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐