简介
- Jetpack Compose:利用声明式编程构建Android原生界面(UI)的 工具包
优势
- 更少的代码、代码量锐减
- 强大的工具/组件支持
- 直观的 Kotlin API
- 简单易用
编程思想
声明性编程范式:声明性的函数构建一个简单的界面组件,无需修改任何 XML 布局,也不需要使用布局编辑器,只需要调用 Jetpack Compose 函数来声明想要的元素,Compose 编译器即会完成后面的所有工作。
简单的组合函数
1
2
3
4
fun Greeting(name: String) {
Text(text = "Hello $name!")
}声明性范式转变:在 Compose 的声明性方法中,微件相对无状态,并且不提供 setter 或 getter 函数。实际上,微件不会以对象形式提供。您可以通过调用带有不同参数的同一可组合函数来更新界面。这使得向架构模式(如 ViewModel)提供状态变得很容易,如应用架构指南中所述。然后,可组合项负责在每次可观察数据更新时将当前应用状态转换为界面。
动态 :组合函数是用 Kotlin 而不是 XML 编写
重组:在 Compose 中,您可以使用新数据再次调用可组合函数。这样做会导致函数进行重组 – 系统会根据需要使用新数据重新绘制函数发出的微件。Compose 框架可以智能地仅重组已更改的组件。
- 可组合函数可以按任何顺序执行
- 可组合函数可以并行运行
- 重组会跳过尽可能多的内容
- 重组是乐观的操作
- 可组合函数可能会非常频繁地运行
开发环境
Arctic Fox 2020-3-1 版本以上,下载最新AndroidStudio
ComposeApp仅支持Kotlin 最低sdk 版本为21,Android 5.0
Gradle Compose相关依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.zm.myjetpackcompose"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
useIR = true
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
kotlinCompilerVersion '1.5.21'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.0-alpha06'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
}需要安装最新Java11, java 8 环境会报以下错误
1
2
3
4
5Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
You can try some of the following options:
- changing the IDE settings.
- changing the JAVA_HOME environment variable.
- changing `org.gradle.java.home` in `gradle.properties`.@Preview生效,则环境正常
UI布局
@Compose
所有关于构建View的方法都必须添加@Compose
注解才可以。并且@Compose
协程的Suspend
的使用方法比较类似,被@Compose
注解的方法只能在同样被@Comopse
解的方法中才能被调用。
1 |
|
@Preview
@Preview
注解的方法可以在不运行App的情况下就可以确认布局的情况。
常用的参数:
name
: String: 为该Preview命名,该名字会在布局预览中显示。showBackground
: Boolean: 是否显示背景,true为显示。backgroundColor
: Long: 设置背景的颜色。showDecoration
: Boolean: 是否显示Statusbar和Toolbar,true为显示。group
: String: 为该Preview设置group名字,可以在UI中以group为单位显示。fontScale
: Float: 可以在预览中对字体放大,范围是从0.01。widthDp
: Int: 在Compose中渲染的最大宽度,单位为dp。heightDp
: Int: 在Compose中渲染的最大高度,单位为dp。
上面的参数都是可选参数,还有像背景设置等的参数并不是对实际的App进行设置,只是对Preview中的背景进行设置,为了更容易看清布局。1
2
3
4
5
6
7
private fun DefaultPreview() {
MyJetpackComposeTheme {
Greeting("Android")
}
}
setContent
setContent的作用是和Layout/View中的setContentView是一样的。
setContent的方法也是有@Compose注解的方法。所以,在setContent中写入关于UI的@Compopse方法,即可在Activity中显示。
1 | override fun onCreate(savedInstanceState: Bundle?) { |
Theme
在创建新的Compose项目时会自动创建一个Theme.kt文件。 我们可以通过更改颜色来完成对主题颜色的设置。
1 | package com.zm.myjetpackcompose.ui.theme |
Modifier
Modifier是各个Compose的UI组件一定会用到的一个类。它是被用于设置UI的摆放位置,padding等信息的类。
padding 设置各个UI的padding
1 | Modifier.padding(10.dp) // 给上下左右设置成同一个值 |
plus 可以把其他的Modifier加入到当前的Modifier中。
1 | Modifier.plus(otherModifier) // 把otherModifier的信息加入到现有的modifier中 |
fillMaxHeight、fillMaxWidth、fillMaxSize 类似于match_parent、填充整个父layout。
1 | Modifier.fillMaxHeight() // 填充整个高度 |
width、heigh、size 设置Content的宽度和高度。
1 | Modifier.width(2.dp) // 设置宽度 |
widthIn, heightIn, sizeIn 设置Content的宽度和高度的最大值和最小值。
1 | Modifier.widthIn(2.dp) // 设置最大宽度 |
gravity 在Column中元素的位置。
1 | Modifier.gravity(Alignment.CenterHorizontally) // 横向居中 |
rtl、ltr 开始布局UI的方向。
1 | Modifier.rtl // 从右到左 |
Column,Row
Column 线性布局 ≈ Android LinearLayout-VERTICAL
Row 水平布局 ≈ Android LinearLayout-HORIZONTAL
Column和Row可以理解为在View/Layout体系中的纵向和横向的ViewGroup。
- Modifier 用上述的方法传入已经按需求设置好的Modifier即可。
- Arrangement.Horizontal, Arrangement.Vertical 需要给Row传入Arrangement.Horizontal,为Column传入Arrangement.Vertical。 这些值决定如何布置内部UI组件。
可传入的值为Center, Start, End, SpaceEvenly, SpaceBetween, SpaceAround。 - Alignment.Vertical, Alignment.Horizontal 需要给Row传入Alignment.Vertical,为Column传入Alignment.Horizontal。 使用方法和Modifier的gravity中传入参数的用法是一样的.
- @Composable ColumnScope.() -> Unit 需要传入标有@Compose的UI方法。但是这里我们会有lamda函数的写法来实现。
1
2
3
4
5Column {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround, verticalAlignment = Alignment.CenterVertically) {
Text(text = "Hello $name!")
}
}
Box
帧布局≈Android FrameLayout,可将一个元素放在另一个元素上,如需在 Row 中设置子项的位置,请设置 horizontalArrangement 和 verticalAlignment 参数。对于 Column,请设置 verticalArrangement 和 horizontalAlignment 参数
ConstraintLayout
需要引入implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02"
列表
可以滚动的布局
1
2
3
4
5
6
7
8//我们可以使用 verticalScroll() 修饰符使 Column 可滚动,但以上布局并无法实现重用,可能导致性能问题
Column(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
messages.forEach { message ->
MessageRow(message)
}
}LazyColumn/LazyRow == RecylerView/listView 列表布局,解决了滚动时的性能问题,LazyColumn和LazyRow之间的区别就在于它们的列表项布局和滚动方向不同。
- 内边距
1
2
3
4
5LazyColumn(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
) {
// ...
}
item间距
1
2
3
4
5LazyColumn(
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
// ...
}浮动列表的浮动标题,使用 LazyColumn 实现粘性标题,可以使用stickyHeader()函数
1
2
3
4
5
6
7
8
9
10
11
12
fun ListWithHeader(items: List<Item>) {
LazyColumn {
stickyHeader {
Header()
}
items(items) { item ->
ItemRow(item)
}
}
}网格布局LazyVerticalGrid
1
2
3
4
5
6
7
8
9
10
fun PhotoGrid(photos: List<Photo>) {
LazyVerticalGrid(
cells = GridCells.Adaptive(minSize = 128.dp)
) {
items(photos) { photo ->
PhotoItem(photo)
}
}
}
- 内边距
自定义布局
通过重组基础布局实现
Canvas绘制
1 | Canvas(modifier = Modifier.fillMaxSize()) { |
结束语
Compose
整体来看,布局实现上相对于xml更加简单高效,也是官方日后力推的开发方式。Compose
写法与Flutter
代码上有很高的相似之处,都是通过响应式的快速搭建UI布局。
(PS:响应式的UI开发模式在大前端的各个语言中越来越相似了)