Hello Compose | 为何要开始学Compose

1,216 阅读5分钟

640.png

一 Compose 概述

本文不会介绍 compose 使用细节,重点在于宏观介绍 compose,将 compose 初步带入大家视野。相当于一个系列的序言吧,后续会再持续更新解析 compose 的使用&设计理念等。

Compose 可以分成两部分看待,Jetpack Compose 和 Compose Multiplatform:

  • Jetpack compose,Android 原生的新 ui 开发工具包,也是本系列讲解的内容。
  • 由 JetBrains 维护的 compose-jb 实现的跨平台 ui 开发工具 Compose Multiplatform。「这不又多了个学习理由:无成本跨平台」

Jetpack Compose 最早是在2019年的 Google I/O 大会上就推出了的首个alpha版本,并于2021年发布了1.0正式版。

经过这几年的更新迭代,Jetpack compose已经相当稳定和成熟了,基本上原生能实现的常用效果,compose 官方或第三方都提供了支持。而且 compose 设计上极容易实现定制化,即使有些效果没支持也可以很方便的开发出来。当然,也可以直接和原生 view 混合使用的。

从官网也可以看到已经有挺多 app 已经逐步迁移到 compose。生态逐渐扩大。相信未来会像 kotlin 一样,全面推广转型。

Clipboard_2023-08-16-17-05-02.png

二 为何学习/迁移 Compose?

一项新技术能得以推广和实现生态化肯定是因为其本身具有突破性的优势,仅仅是强行施压,开发者们并不会买单。那么 compose 是有哪些优点能让迁移者痴迷?

2.1 快人一步:更少代码

与传统 view 相对,compose能用更少的代码实现相同的效果。代码少就意味着开发快,更容易维护

Zepeto的迁移中,在多功能列表界面,代码量减少了 60%

Clipboard_2023-08-17-10-53-04.png

以列表为例,实现简单的效果。

Clipboard_2023-08-17-14-55-49.png

按传统 view 的方式,item.xml 以及为了 10dp 的圆角和 circleImage 得声明xml,总共就三个 xml 文件,然后还得在代码上声明DiffUtil.ItemCallback,Recycelerview.Adapter,RecyclerView.ViewHolder等一套重复化代码。

到了 compose 中,所有的功能就以下代码量


    LazyColumn(modifier = Modifier.background(color = Color.Black)) {

        items(items = fakeData, key = { it.id }) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(80.dp)
                    .padding(horizontal = 20.dp)
                    .clip(RoundedCornerShape(10.dp))
                    .background(color = Color.White)
                    .padding(10.dp),
                verticalAlignment = Alignment.CenterVertically
                ) {
                Image(
                    painter = painterResource(id = R.drawable.compose),
                    contentDescription = "",
                    modifier = Modifier.size(60.dp).border(width = 2.dp, color = Color.Black, shape = CircleShape)
                )
                Spacer(modifier = Modifier.width(10.dp))
                Text(text = it.content, color = Color.Black)
            }
            Spacer(modifier = Modifier.height(10.dp))

        }
    }

这也是我个人觉得 compose 会得以推广的重要原因,什么性能什么声明 ui,写起来快就完事了,大堆需求等着呢

2.2 易用&丰富的 api

compose api 设计上以简单使用/定制为宗旨,同时具有丰富的内置功能,能大大满足我们日常开发上的需求。

2.2.1 布局简单

与传统 View 相比,Compose的布局要相对简单得多。核心常用的只有三个,columnRowBox

Clipboard_2023-08-17-15-33-18.png

Column就是让控件纵向排列,Row就是让控件横向排列。Column和Row对应的其实就是View当中的LinearLayout。

而Box对应的是View当中的FrameLayout。

ok,没有了,这就满足我们开发需要了,没有RelativeLayout和ConstraintLayout了。回想下,使用ConstraintLayout是为了解决嵌套布局性能问题,不然linearLayout 和 framelayout 基本就满足各种复杂 ui 了。

由于 Compose 可以避免多次测量,因此可以根据需要进行深层次嵌套,而不会影响性能!!! 所以columnRowBox基本就能满足我们的复杂界面了。

当然,考虑到用户习惯,Google 也提供了ConstraintLayout compose 版

2.2.2 功能丰富

compose 内置了很多有用的功能,比如拖拽,滚动,手势处理,SwipeToDismiss和动画效果等

以倒计时UI为例

Screen_recording_20230817_155818.gif

代码量只有以下:

AnimatedContent(
targetState = count,
transitionSpec = {
    if (targetState > initialState) {
        slideInVertically { height -> height } + fadeIn() togetherWith
                slideOutVertically { height -> -height } + fadeOut()
    } else {
        slideInVertically { height -> -height } + fadeIn() togetherWith
                slideOutVertically { height -> height } + fadeOut()
    }.using(SizeTransform(clip = false))
}
) { targetCount ->
    Text(text = "$targetCount")
}

各种定制化效果,都能够很容易的实现

2.3 声明式 UI 框架

一种编程思想吧,个人理解是界面由 state 控制,state 改变界面自动刷新。 也就是说不用像以前一样 setText,setVisibility。 这个概念言语上比较难以表达,按这种方式写的 ui 呢,就比较容易自测而且难出错,当然,代码量也会低很多。 还是以常见的界面 error 状态,loading 状态,success 状态切换为例 以前的写法是

when (status) {
        Status.SUCCESS -> {
            contentView.visibility = View.VISIBLE
            loadingView.visibility = View.GONG
            errorView.visibility = View.GONG
        }
        Status.LOADING -> {
            loadingView.visibility = View.VISIBLE
            contentView.visibility = View.GONG
            errorView.visibility = View.GONG
        }
        Status.ERROR -> {
            errorView.visibility = View.VISIBLE
						contentView.visibility = View.GONG
            loadingView.visibility = View.GONG
        }
    }

在 compose 世界里,

when (status) {
        Status.SUCCESS -> {
            ContentView()
        }
        Status.LOADING -> {
            LoadingView()
        }
        Status.ERROR -> {
            ErrorView()
        }
    }

不再需要关心如何隐藏不同的 view,只需要声明,哪个状态下界面长什么样即可。当状态改变时,compose 会自动重组刷新界面。也就是会自动帮我们完成一系列 findview& setVisibility。

2.4 无需App Building的预览 &交互 &动画

Android studio 直接预览 ui模拟手势交互以及按帧查看动画&调试动画值,不再需要build &run 整个 app 项目

2.4.1 无需运行,直接模拟手势交互

1_loC7Y0RrCVAbSC48mGzETA.gif

1_NqVwAaURsVNLBEcCeIlwYQ.gif

2.4.2 无需运行,按帧查看动画效果 &调试动画值

1_wnS1lPqy8XEo5TmzGCh6xg.gif

Clipboard_2023-08-17-16-49-51.png

2.4.3 Live Edit

Live Edit,实时编辑:界面修改无需重新rebuild&run,会自动刷新到真机或模拟机上

LiveEditShortVideo.gif

三 后续

本文只是作为一个系列的序言吧,后续会出更多教程慢慢上手,如布局、modifier、size,生命周期,side-effect,windowInset 等等。 我也是个初学者,有什么错误和遗漏大家帮忙补补哈。

一键三连

如果觉得这篇内容对你有所帮忙,一键三连支持下(👍)

关于纠错和建议:欢迎直接在留言分享记录(🌹)