简介
Jetpack Compose是用于构建原生Android界面的新工具包。它是一种声明式的UI布局,其官方声称可简化并加快Android上的界面开发,使用更少的代码、强大的工具和直观的Kotlin API,快速让应用生动而精彩。
官网:https://developer.android.com/jetpack/compose?hl=zh-cn
我这里也写了一个Compose的Demo,可以对照着看:https://github.com/dreamgyf/ComposeDemo
这个Demo实现了:
- Compose替代传统布局

- 网格列表效果,类似于传统布局中的RecyclerView配合GridLayoutManager

- 在传统View中使用Compose 
- 在Compose中使用传统View 
- 自定义布局 
前置工作
使用Jetpack Compose需要先引入一些依赖:
| 1 | dependencies { | 
可组合函数
Jetpack Compose是围绕着可组合函数构建起来的,这些函数以程序化方式定义应用的界面,只需描述应用界面的外观并提供数据依赖项,而不必关注界面的构建过程。此类函数有几个要点:
- 所有可组合函数必须使用@Composable注解修饰
- 可组合函数可以像正常函数一样接受参数
| 1 | 
 | 
- 可组合函数内部可以书写正常代码(譬如可以通过if else控制显示的控件)
| 1 | 
 | 
单位
Android常用的单位dp,sp等,在Compose中以类的形式被定义,使用的方式也很简单,Compose借助了kotlin的扩展属性,扩展了Int,Double,Float三个基础类,使用方式如下:
| 1 | //dp | 
资源
如何在Compose中使用资源呢,可以通过xxxResource方法
| 1 | //图片资源 | 
Modifier
Modifier是Compose中的布局修饰符,它控制了布局的大小,padding,对齐,背景,边框,裁切,点击等属性,几乎所有的Compose布局都需求这项参数,是Compose布局中的重中之重
这里介绍一些常用的基本属性,文中没列到的属性可以去官网查看:https://developer.android.com/jetpack/compose/modifiers-list?hl=zh-cn
尺寸
- fillMaxWidth和- fillMaxHeight相当于- xml布局中的- match_parent
- fillMaxSize相当于同时设置了- fillMaxWidth和- fillMaxHeight
- wrapContentWidth和- wrapContentHeight相当于- xml布局中的- wrapContent
- wrapContentSize相当于同时设置了- wrapContentWidth和- wrapContentHeight
- width和- height则是设置固定宽高,单位为- Dp
- size相当于同时设置了- width和- height
- weight属性仅在- Row或- Column的内部作用域中可以使用,相当于传统- LinearLayout布局中的- weight属性
padding
padding方法有几个重载,这些API很简单,看参数就很容易能明白意思
对齐
align属性,使控件可以在父布局中以一种方式对齐,相当于xml布局中的layout_gravity属性。另外还有alignBy以及alignByBaseline属性可以自行研究
绘图
- background设置背景,不过不能设置图片,如果想以图片作为背景可以使用- Box布局,在底部垫一个- Image控件
- alpha设置透明度
- clip裁剪内容,这个功能很强大,可以直接将视图裁出圆角,圆形等形状
操作
- clickable方法,可以设置控件的点击事件回调
- combinedClickable方法,可以设置控件的点击、双击、长按事件回调
- selectable方法,将控件配置为可点击,同时可以设置点击事件
滚动
- horizontalScroll:使控件支持水平滚动
- verticalScroll:使控件支持垂直滚动
注意事项
在Modifier中设置属性的前后顺序是很重要的,譬如想要一个背景为蓝色的圆角布局,需要先设置clip,再设置background,反过来background会超出圆角范围
Spacer
Compose中没有了margin的概念,可以用Spacer替代,Spacer为留白的意思,使用起来也很简单
| 1 | //水平间隔8dp | 
基础布局
Row & Column
这是两个基本布局组件,其中Row为水平布局,Column为垂直布局,他们俩接受的参数相似,其中两个参数为horizontalArrangement和verticalAlignment,他们一个表示水平布局方式,一个表示垂直布局方式,他们默认值为START和TOP,这两个参数用起来就和传统布局的gravity参数一样
Box
Box也是一种基本布局组件,Box布局中的组件是可以叠加的,类似传统布局中的FrameLayout,可以通过contentAlignment参数调整叠加的方式,其默认值为TopStart,叠加到左上角,这个参数也和FrameLayout的gravity参数一样
基础控件
Text
文本控件,对应传统控件TextView,它有以下一些属性
| 属性 | 说明 | 
|---|---|
| text | 文本内容 | 
| color | 文字颜色 | 
| fontSize | 文字大小 | 
| fontStyle | 文本样式(可以设置斜体) | 
| fontWeight | 字重(粗体等) | 
| fontFamily | 字体 | 
| letterSpacing | 文字间距 | 
| textAlign | 文本对齐方式 | 
| lineHeight | 行高 | 
| maxLines | 最大行数 | 
| … | … | 
Image
图片控件,对应传统控件ImageView,它有以下一些属性
| 属性 | 说明 | 
|---|---|
| painter | 图片内容 | 
| contentDescription | 无障碍描述(可为null) | 
| alignment | 对齐方式 | 
| contentScale | 缩放方式(和scaleType属性类似) | 
| alpha | 透明度 | 
| … | … | 
在开发中经常会面对从网络价值图片的情况,这时候可以借助一些第三方库来解决,这里以coil库为例:
- 先添加依赖
| 1 | implementation "io.coil-kt:coil-compose:1.4.0" | 
- 使用
| 1 | Image( | 
列表
Compose有两种组件LazyRow和LazyColumn,一种水平,一种垂直,对应着传统UI中的RecyclerView,用这些组件可以方便的构建列表视图,它们需要提供一个LazyListScope.()块描述列表项内容
LazyListScope的DSL提供了多种函数来描述列表项:
| 1 | //用于添加单个列表项 | 
示例:
| 1 | val list = mutableListOf(0, 1, 2, 3, 4) | 
可以使用contentPadding为内容添加内边距,使用verticalArrangement或horizontalArrangement,以Arrangement.spacedBy()为列表项之间添加间距
状态
在Compose中,数据的更新和传统命令式UI不同,是通过一种可观察类型对象,当一个可观察类型对象发生改变时,这个对象对应观察的部分会发生重组,从而自动更新UI
可观察类型MutableState<T>通常是通过mutableStateOf()函数创建的,这个对象的value发生变化时,对应UI也会跟着随之变化
| 1 | //这里使用了kotlin的by关键字,是一种代理模式 | 
关于Context
在Compose中可以通过LocalContext.current获得当前Context
在传统View中使用Compose
可以在一个传统布局xml中插入一个ComposeView
| 1 | 
 | 
然后在代码中设置这个ComposeView
| 1 | findViewById<ComposeView>(R.id.compose_view).setContent { | 
在Compose中使用传统View
可以使用AndroidView这个composable函数,这个函数接受一个factory参数,这个参数接受一个Context,用于构建传统View,要求返回一个继承自View的对象
| 1 | 
 | 
自定义UI
在Compose中,如果想要自定义一些简单的UI是很简单的,只需要写一个Composable函数就可以了,我们主要学习一下怎么自定义一些复杂的UI
我们先看一下怎么自定义一个布局,对应着传统UI中的ViewGroup,以一个简单的例子来说,我们自定义一个布局,让其中的子布局呈左上到右下依次排列:
| 1 | 
 | 
我们再看一个使用Canvas自定义View的方式,这个更简单,就是画一条水平线:
| 1 | 
 | 
我们将两者一起用一下看看效果
| 1 | 
 | 

其实Compose中的自定义UI的思路和传统自定义View是一样的,只不过需要熟悉Compose中的各种Api才能灵活运用它
