Jetpack Compose 和 View 的互操作性,这个回答让我错失 offer
Jetpack Compose Interoperability
==============================================================================================
Compose 风这么大, 对于已有项目使用新技术, 难免会担心兼容性. 对于 Compose 来说, 至少和 View 的结合是无缝的. (目前来讲, 已有项目要采用 Compose, 可能初期要解决的就是升级 gradle plugin, gradle, Android Studio, kotlin 之类的问题.)
构建 UI 的灵活性还是有保证的:
新界面想用 Compose, 可以.
Compose 支持不了的, 用 View.
已有界面不想动, 可以不动.
已有界面的一部分想用 Compose, 可以.
有的 UI 效果想复用之前的, 好的, 可以直接拿来内嵌.
本文就是一些互相调用的简单小 demo, 初期用的时候可以复制粘贴一下很趁手.
官方文档: developer.android.com/jetpack/com…
在 Activity 或者 Fragment 中全部使用 Compose 来搭建 UI
Use Compose in Activity
class ExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { // In here, we can call composables!
MaterialTheme {
Greeting(name = "compose")
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
Use Compose in Fragment
class PureComposeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
MaterialTheme {
Text("Hello Compose!")
}
}
}
}
}
ComposeView 内嵌在 Xml 中:
一个平平无奇的 xml 布局文件中加入ComposeView
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/hello_world"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello from XML layout" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="m
atch_parent"
android:layout_height="match_parent" />
</LinearLayout>
使用的时候, 先根据 id 查找出来, 再 setContent:
class ComposeViewInXmlActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_compose_view_in_xml)
findViewById<ComposeView>(R.id.compose_view).setContent {
// In Compose world
MaterialTheme {
Text("Hello Compose!")
}
}
}
}
动态添加 ComposeView
在代码中使用addView()
来添加 View 对于ComposeView
来说也同样适用:
class ComposeViewInViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(LinearLayout(this).apply {
orientation = VERTICAL
addView(ComposeView(this@ComposeViewInViewActivity).apply {
id = R.id.compose_view_x
setContent {
MaterialTheme {
Text("Hello Compose View 1")
}
}
})
addView(TextView(context).apply {
text = "I'm am old TextView"
})
addView(ComposeView(context).apply {
id = R.id.compose_view_y
setContent {
MaterialTheme {
Text("Hello Compose View 2")
}
}
})
})
}
}
这里在LinearLayout
中添加了三个 child: 两个ComposeView
中间还有一个TextView
.
起到桥梁作用的ComposeView
是一个ViewGroup
, 它本身是一个 View, 所以可以混进 View 的 hierarchy tree 里占位, 它的setContent()
方法开启了 Compose 世界的大门, 在这里可以传入 composable 的方法, 绘制 UI.
都用 Compose 搭建 UI 了, 什么时候会需要在其中内嵌 View 呢?
要用的 View 还没有 Compose 版本, 比如
AdView
,MapView
,WebView
.有一块之前写好的 UI, (暂时或者永远)不想动, 想直接用.
用 Compose 实现不了想要的效果, 就得用 View.
在 Compose 中加入 Android View
例子:
@Composable
fun CustomView() {
val state = remember { mutableStateOf(0) }
//widget.Button
AndroidView(
factory = { ctx ->
//Here you can construct your View
android.widget.Button(ctx).apply {
text = "My Button"
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
setOnClickListener {
state.value++
}
}
},
modifier = Modifier.padding(8.dp)
)
//widget.TextView
AndroidView(factory = { ctx ->
//Here you can construct your View
TextView(ctx).apply {
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
}
}, update = {
it.text = "You have clicked the buttons: " + state.value.toString() + " times"
})
}
这里的桥梁是AndroidView
, 它是一个 composable 方法:
@Composable
评论