Android 技术前沿:Jetpack Compose
简介
Jetpack Compose:利用声明式编程构建Android原生界面(UI)的 工具包
优势
代码更少,大大减少了代码量、强大的工具/组件支持、直观的Kotlin API、易于使用
编程思想
声明性编程范例:声明性函数在不修改任何XML布局或使用布局编辑器的情况下构建一个简单的接口组件。您只需要调用Jetpack Compose函数来声明所需的元素,Compose编译器就会这样做所有工作 Compose可以通过并行运行可组合函数来优化重组,这样Compose就可以利用多个核心并以较低的优先级运行可组合函数(不在屏幕上)这种优化意味着可组合函数可以在后台线程池中执行。如果可组合函数调用ViewModel上的函数,则Compose可以同时从多个线程调用该函数调用可组合函数时,调用可能发生在与调用方不同的线程上,这意味着您应该避免使用修改可组合lambda中变量的代码,这既是因为此类代码不是线程安全的代码,也是因为它是可组合lambda不允许的副作用重组将跳过尽可能多的可组合函数和lambda重组是一项乐观的行动,可能会被取消可组合函数的运行频率可能与动画的每一帧相同
环境
Gradle Compose相关依赖
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.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
kotlinOptions {
jvmTarget = '1.8'
useIR = true//
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
kotlinCompilerVersion '1.5.10'
}
buildFeatures {
compose true
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
布局
Android传统上是从xml状态关系改变过来的,程序员需要大量的代码来维护UI界面,以实现界面状态的正确性,这既耗时又费力。即使在MVVM架构的帮助下,也需要维护状态,因为只有一组布局。声明式和传统XML实现的区别在于,Compose声明式布局直接重建UI,因此不会出现状态问题Text:Compose提供基本的BasicText和BasicTextField,它们是显示文本和处理用户输入的主要功能。Compose还提供了更高级的文本和文本字段 重新组织文本->按钮
@Composable
fun ClickCounter(clicks: Int, onClick: () -> Unit) {
Button(onClick = onClick) {
Text("I've been clicked $clicks times")
}
}
Modifier可以修改控件的位置、高度、边距、对齐方式等等
//`padding` 设置各个UI的padding。padding的重载的方法一共有四个。
Modifier.padding(10.dp) // 给上下左右设置成同一个值
Modifier.padding(10.dp, 11.dp, 12.dp, 13.dp) // 分别为上下左右设值
Modifier.padding(10.dp, 11.dp) // 分别为上下和左右设值
Modifier.padding(InnerPadding(10.dp, 11.dp, 12.dp, 13.dp))// 分别为上下左右设值
//这里设置的值必须为`Dp`,`Compose`为我们在Int中扩展了一个方法`dp`,帮我们转换成`Dp`。
//`plus` 可以把其他的Modifier加入到当前的Modifier中。
Modifier.plus(otherModifier) // 把otherModifier的信息加入到现有的modifier中
//`fillMaxHeight`,`fillMaxWidth`,`fillMaxSize` 类似于`match_parent`,填充整个父layout。
Modifier.fillMaxHeight() // 填充整个高度
//`width`,`heigh`,`size` 设置Content的宽度和高度。
Modifier.width(2.dp) // 设置宽度
Modifier.height(3.dp) // 设置高度
Modifier.size(4.dp, 5.dp) // 设置高度和宽度
//`widthIn`, `heightIn`, `sizeIn` 设置Content的宽度和高度的最大值和最小值。
Modifier.widthIn(2.dp) // 设置最大宽度
Modifier.heightIn(3.dp) // 设置最大高度
Modifier.sizeIn(4.dp, 5.dp, 6.dp, 7.dp) // 设置最大最小的宽度和高度
//`gravity` 在`Column`中元素的位置。
Modifier.gravity(Alignment.CenterHorizontally) // 横向居中
Modifier.gravity(Alignment.Start) // 横向居左
Modifier.gravity(Alignment.End) // 横向居右
//`rtl`, `ltr` 开始布局UI的方向。
Modifier.rtl // 从右到左
列表
可以滚动的布局
Column (
modifier = Modifier.verticalScroll(rememberScrollState())){
messages.forEach { message ->
MessageRow(message)
}
}
内边距
LazyColumn(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
) {
// ...
}
item间距
LazyColumn(
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
// ...
}
浮动列表的浮动标题
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListWithHeader(items: List<Item>) {
LazyColumn {
stickyHeader {
Header()
}
items(items) { item ->
ItemRow(item)
}
}
}
网格布局
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PhotoGrid(photos: List<Photo>) {
LazyVerticalGrid(
cells = GridCells.Adaptive(minSize = 128.dp)
) {
items(photos) { photo ->
PhotoItem(photo)
}
}
}
自定义布局
Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
val canvasWidth = size.width
val canvasHeight = size.height
drawCircle(
color = Color.Blue,
center = Offset(x = canvasWidth / 2, y = canvasHeight / 2),
radius = size.minDimension / 4
)
}
//drawCircle 画圆
//drawRectangle 画矩形
//drawLine //画线;
|