[Android Compose] 二、Compose 初见+线性布局 | 七日打卡

2,621 阅读4分钟

上一篇介绍了 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 的短短几十行代码也遇到了坑:

  1. 加载 drawable 的 ic_launcher 出现崩溃,未解决
  2. Preview 更新不及时,修改后需要手动刷新,甚至很多时候需要重新 build 项目才能显示更新
  3. 官方文档中提到的 Stack 布局(对应 FrameLayout)找不到,应该是被优化掉了或者改了名字

知易行难啊,搭建环境和写代码的过程中遇到很多坑,进度比预期的慢了一些,Compose 的约束布局要放到明天来做了。

如果能坚持下来七日打卡,我会再总结一篇完整的文章详细说明一下 Compose 的现状的,希望可以达成目标吧。

(都看到这里了,赏个赞再走如何?)