上一篇介绍了 Compose 的功能,以及其本质还是用 Kotlin 函数描述 UI。接下来开始学习使用方式,跟学习 xml 时一样,我们从布局开始,再引出一些常用控件。
零、环境搭建
由于 Compose 还是 alpha 发布,API 不稳定且必须在 Android Studio 的 Preview 版本中才能使用,甚至要求 gradle 插件也是 alpha 版本才行,现在做环境搭建的介绍很可能马上就变成错误的说明。在发布文章的这天,官网的教程和文档都是过时的,如果想自己试试,建议对比一下 github.com/android/com… 的 demo,选择更高的版本号。
环境配置好之后,还要在代码中配置 @Preview 函数才能预览,建议使用这样的结构:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { // 相当于 setContentView
Content()
}
}
@Preview
@Composable
fun Preview() { //注意:@Preview 不能有参数
Content()
}
// Content 是一个 @Composable
Preview 可以配置多个,每个 Preview 都会生成一个预览图。
在 Compose 框架中,UI 由一系列环环相扣的 Composable 组成,Composable 用注解声明。Composable 与 View 相似,大部分场景使用框架提供好的预置 Composable 就好了,特殊场景也可以自定义 Composable 实现需求或者优化性能。按惯例,我们从预置 Composable 学起。
一、Column、Row
说起布局,初学者通常从 LinearLayout 和 FrameLayout 入手学习,再逐渐扩展到 RelativeLayout、ConstraintLayout(当然,时代变了,现在的年轻人也很有可能是从 ConstraintLayout 开始学的)。这些布局的作用是规划子View的排列方式,确定子View的位置,其本身只会绘制背景。
无论是用 xml 还是用 Compose,编译后的产物依然是 View,我们过去的经验依然有用,所以通过在 Compose 中寻找那些我们熟悉的概念,就可以将二者融会贯通。
Column 和 Row 分别是 LinearLayout 的 vertical 模式和 horizontal 模式,其内部子 View 会按顺序紧密排列,而 Column 和 Row 本身都默认是 wrap_content 的,并且没有类似于 match_parent 的设置项。(Modifier.fillMax 系列函数会直接填满屏幕)
LinearLayout 还有一个常用属性是 gravity,在 Compose 中等价于 Row 的 verticalAlignment 和 Column 的 horizontalAlignment。
二、举个栗子
太难的栗子还没有尝试,这里模仿教程中的样式做一个常见的用户信息展示,效果大概这样:
上面的效果图是 Android Studio 中预览的 Composable 完整截图,Composable 的预览与 xml 不同,不会模拟显示在手机屏幕中的样子,而是每个 Preview 生成一小块自己的内容。预览效果还算不错。
写一个 Content 实现效果:
@Composable
fun Content() {
val imageRes = imageResource(id = R.drawable.juejin_avatar_300x300)
Row(
modifier = Modifier
.background(Color(0xFFBCE9FF))
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
imageRes,
modifier = Modifier
.preferredSize(60.dp, 60.dp)
.padding(8.dp)
.background(Color(0xFF343434))
.clip(CircleShape)
)
Column(
modifier = Modifier.background(Color(0xFFE0FFE3)),
horizontalAlignment = Alignment.Start
) {
Row(
modifier = Modifier.background(Color(0xFFFFE5E0)),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "万俟霜风",
style = TextStyle(
fontSize = 22.sp
),
modifier = Modifier
.background(Color(0xFF868FBA))
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "@罗德岛",
color = Color.Blue,
style = TextStyle(
fontSize = 20.sp
),
modifier = Modifier.background(Color(0xFF96BA86))
)
}
Text(
text = "ko~ko~da~yo~",
color = Color(0xff666666),
modifier = Modifier.background(Color(0x00ffcc)),
style = TextStyle(
fontSize = 16.sp
)
)
}
}
}
看这错落有致的代码排版,是不是血压升高了?这是写完之后用默认的代码风格格式化之后的样子,可见复杂项目中 Compose 的使用还需要一些其他的代码规范,比如尽量拆成多个小的 Composable 函数、复用 Modifier 等。
看看运行后的效果吧:
三、初见的惊喜和坑
Android Studio 对 Compose 的支持让我挺意外的,在 Activity 中的预览效果和左侧的颜色选择器和图片查看器都跟 xml 中相同,大大降低了开发中的调试难度,可以说是增添了对 Compose 的几分期待。
另外,Compose 的 Color 类终于有直接传入十六进制数字的构造函数了,太舒服了。表示 dp 和 sp 的扩展函数也相当优秀,简洁明确可读性极强。
写 demo 的短短几十行代码也遇到了坑:
- 加载 drawable 的 ic_launcher 出现崩溃,未解决
- Preview 更新不及时,修改后需要手动刷新,甚至很多时候需要重新 build 项目才能显示更新
- 官方文档中提到的 Stack 布局(对应 FrameLayout)找不到,应该是被优化掉了或者改了名字
知易行难啊,搭建环境和写代码的过程中遇到很多坑,进度比预期的慢了一些,Compose 的约束布局要放到明天来做了。
如果能坚持下来七日打卡,我会再总结一篇完整的文章详细说明一下 Compose 的现状的,希望可以达成目标吧。
(都看到这里了,赏个赞再走如何?)