前两天闲来无事,翻了翻Google的Maven仓库看看Room有没有什么更新,意外地发现有新的东西出现了:
androidx.compose:compose-compiler:0.1.0-dev01
androidx.compose:compose-runtime:0.1.0-dev01
androidx.ui:ui-core:0.1.0-dev01
androidx.ui:ui-layout:0.1.0-dev01
androidx.ui:ui-framework:0.1.0-dev01
androidx.ui:ui-animation:0.1.0-dev01
androidx.ui:ui-animation-core:0.1.0-dev01
androidx.ui:ui-android-text:0.1.0-dev01
androidx.ui:ui-material:0.1.0-dev01
androidx.ui:ui-tooling:0.1.0-dev01
androidx.ui:ui-platform:0.1.0-dev01
androidx.ui:ui-vector:0.1.0-dev01
androidx.ui:ui-foundation:0.1.0-dev01
androidx.ui:ui-text:0.1.0-dev01
androidx.ui:ui-test:0.1.0-dev01
这让我有点小激动哈,直觉告诉我我们可以尝鲜Jetpack Compose了!但是很快我又觉得不对劲了,我记得Compose好像需要AS的插件来配合才能实现,最近的AS更新好像也没有提到相关的东西啊,而且androidx.compose
下的文件是空的,除了光秃秃的META-INF/MANIFEST.MF
文件啥也没有,这是什么操作?然后大神Ian Lake也没在推特上提到关于Compose的任何事情,难道是误操作?
如果我把它当作一次失误,那我们的故事也就到这里结束了。但是我实在按捺不住好奇心,而且真的很想尝尝鲜,(主要还是真的很闲)就决定自己摸索一番。
功夫不负有心人,经过一番折腾,我发现Google并没有按之前所说开发一个定制的Kotlin编译器,而是采用注解处理+反射来开发Compose,那之前由于Kotlin编译器不开放而无法在早期尝鲜Compose的问题就不存在了,也就是说现在只要AS版本在3.5.1以上就都能使用Compose!
还等什么,一起来看看Compose怎么玩!
首先把涉及到的依赖添加进来:
implementation "androidx.compose:compose-runtime:$compose_version"
kapt "androidx.compose:compose-compiler:$compose_version"
implementation "androidx.ui:ui-material:$compose_version"
implementation "androidx.ui:ui-foundation:$compose_version"
implementation "androidx.ui:ui-layout:$compose_version"
implementation "androidx.ui:ui-android-text:$compose_version"
implementation "androidx.ui:ui-text:$compose_version"
然后我们就可以编写我们的界面啦,我们通过组合其它小控件来生成自己的UI单元,以Composable方法的形式由小到大组合成我们的界面,这是核心,剩下的我们只需要去了解官方提供给我们使用的小控件怎么使用就好了。我觉得Compose也采用了Flutter那种“一切皆控件”的思想,提供的构建块跟Flutter神似,我总有一种我在写Flutter应用的感觉,不仅命名相似,提供的功能与对属性的抽象也大致相同,比如Text
,比如FAB
,甚至连在Canvas
绘制都很相似,它也用Column
来表示一个列,用Center
把子控件居中,用Padding
设置内边距,有专门的Style
控件管理样式,也实现了FlexBox
模型等等,稍微熟悉Flutter代码的同学都能很快上手。当然了,这篇文章主要目的是对Compose有个感性的认识,对具体控件的深入了解我们放到后面的文章中去。
现在我想在屏幕中间放置了一个Text
来显示当前的点击数,然后在右下角放置了一个FAB
来更新点击数。
@Composable
fun content() = MaterialTheme {
FlexColumn {
inflexible {
TopAppBar<MenuItem>(
title = { Text("Jetpack Compose Sample") }
)
}
expanded(1F) {
Center {
Column {
Center {
Text(
text = "You have pushed the button this many times:",
style = TextStyle(
fontSize = Sp(15F),
fontWeight = FontWeight.bold
)
)
}
Center {
Text(
text = "${count.cnt}",
style = TextStyle(
color = Color.Gray,
fontSize = Sp(22F),
fontWeight = FontWeight.bold
)
)
}
}
}
}
}
Align(Alignment.BottomRight) {
fab()
}
}
@Composable
fun fab() {
Row {
val onAddClick: () -> Unit = {
count.add()
}
Padding(
padding = EdgeInsets(all = Dp(8F))
) {
FloatingActionButton(
color = Color(0xff2196f3),
icon = imageFromResource(
resources,
R.drawable.add
),
onClick = onAddClick
)
}
}
}
这样我们就实现了我们的布局,b把它应用到我们的Activity非常地简单,只需要把我们之前设置布局文件的代码改成如下代码就可以了:
setContent { content() }
眼熟的朋友可能已经发现了我这是模仿了Flutter初始化工程的界面:
根据Compose的描述,它是一个响应式Ui框架,按理来说只要应用了@Model
注解,就能像Flutter一样,点击下方的FAB会更新屏幕中间的数字,但实际界面是成功用“Compose”的方式跑起来了,响应更新界面却并未生效,这个bug还待官方处理,大家尝鲜的时候先画画界面玩玩好了。
就结果而言,我觉得Compose是一种对开发形式的创新,用标记语言描述布局结构不再是我们唯一的选择,只是目前还不知道这种UI构建模式会怎样把MotionLayout
融入进来,毕竟后者也提供了很多创造性的功能。而且我觉得Google从编译器的方式迁移到注解+反射的方式挺好,但是这样的方式相比于布局文件能带来多大的性能提升目前还未可知,不过当前毕竟是dev build,未来改动还会很大,说不定后期又采用编译器的方式了呢。不管怎样,Compose核心思想不会变的(比如composable函数)。
代码地址:Jetpack Compose Demo