Android Jetpack Compose快速上手
一、Jetpack Compose简介
Jetpack Compose是Google推出的一个用于构建原生Android 界面的工具包,旨在帮助开发者更快、更轻松地在Android 平台上构建原生客户端应用。同时,作为全新的声明式的UI框架,Jetpack Compose可以使用声明式Kotlin API取代Android 传统的xml布局。
那什么是声明式呢?要搞清楚这个问题,我们需要布局开发中的另外一个概念:命令式。事实上,传统的使用xml布局方式就是命令式。在传统的命令式开发流程中,我们首先需要使用xml来创建布局,然后再通过findViewById方法获取控件,最后再绑定数据。而在声明式开发中,我们可以直接调用compose的库组件进行渲染,比如:
@Composable
fun ShowText(content: String){
Text(text = content)
}
事实上,除了Jetpack Compose,Flutter、React Native和Swift-UI 等框架都是声明式的,可以说,前端的大部分的页面渲染都可以使用声明式来完成。
二、快速上手
2.1 环境搭建
工欲善其事,必先利其器。目前,Android Studio对Jetpack Compose 已经有了很好的支持,我们只需要下载最新版的Android Studio即可。
安装完成之后,我们可以下载托管在github上的 Jetpack Compose 示例应用来体验Jetpack Compose的魅力。
2.2 创建Jetpack Compose应用
为了帮助开发者快速地上手Jetpack Compose,Android Studio提供了支持Jetpack Compose 的新项目模板。我们只需要打开 Android Studio,然后在菜单栏中依次选择 【File】->【New】->【New Project】 ->【Empty Compose Activity】。
然后,点击【Next】按钮,填写 Name、Package name 和 Save location等参数即可完成Jetpack Compose项目的创建。工程创建完成之后,Jetpack Compose项目会默认添加如下一些依赖。
dependencies {
implementation("androidx.compose.ui:ui:1.2.1")
// Tooling support (Previews, etc.)
implementation("androidx.compose.ui:ui-tooling:1.2.1")
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
implementation("androidx.compose.foundation:foundation:1.2.1")
// Material Design
implementation("androidx.compose.material:material:1.2.1")
// Material design icons
implementation("androidx.compose.material:material-icons-core:1.2.1")
implementation("androidx.compose.material:material-icons-extended:1.2.1")
// Integration with observables
implementation("androidx.compose.runtime:runtime-livedata:1.2.1")
implementation("androidx.compose.runtime:runtime-rxjava2:1.2.1")
// UI Tests
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.2.1")
}
2.3 原有项目添加Jetpack Compose
当然,使用Android Studio提供的Jetpack Compose 模板来创建项目是最简单的,如果对于老的Android项目,我们需要怎么处理呢?
首先,打开项目的build.gralde文件,确保Kotlin的版本是1.4.30以上的版本。
plugins {
...
id 'org.jetbrains.kotlin.android' version '1.5.30' apply false
}
然后,打开app/build.gralde文件,添加或修改如下一些配置:
``` android {
// 1、确保最低sdk版本为21或者更高
defaultConfig {
...
minSdkVersion 21
}
buildFeatures {
// 2、开启 jetpack compose 支持
compose true
}
...
// 3、设置java 和 kotlin 编译器版本为java8或者更高的版本
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// 4、添加kotlin编译器扩展版本
composeOptions {
kotlinCompilerExtensionVersion '1.3.0'
}
} ```
然后,添加Jetpack Compose 开发需要的一些依赖库。
dependencies {
// Integration with activities
implementation 'androidx.activity:activity-compose:1.5.1'
// Compose Material Design
implementation 'androidx.compose.material:material:1.2.1'
// Animations
implementation 'androidx.compose.animation:animation:1.2.1'
// Tooling support (Previews, etc.)
implementation 'androidx.compose.ui:ui-tooling:1.2.1'
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.2.1'
}
2.4 迁移到 Compose
对于传统的xml布局,我们如何将其迁移到 Jetpack Compose。加入,我们在 XML 布局中有如下一段代码。
```
<...>
```
为了将其迁移到 Compose,我们可以将 TextView 替换为保留了相同布局参数和 id 的 ComposeView,如下所示。
```
<...>
```
然后,在使用了该XML布局的Activity或Fragment中获取ComposeView,然后调用setContent方法并向其中添加Compose内容。
```
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
val greeting = findViewById
@Composable private fun Greeting() { Text( text = stringResource(R.string.greeting), style = MaterialTheme.typography.h5, modifier = Modifier .fillMaxWidth() .padding(horizontal = dimensionResource(R.dimen.margin_small)) .wrapContentWidth(Alignment.CenterHorizontally) ) } ```
三、Compose工具
事实上,为了支持Jetpack Compose 的快速开发,Android Studio引入了许多专用于Jetpack Compose 的新功能。它支持使用代码优先方法,同时提高了开发者的工作效率,因为开发者不必在设计界面或代码编辑器之间二选一。
而基于View的界面与Jetpack Compose之间的一个基本区别在于,Compose不依赖View来呈现其可组合项。同时,Android Studio 为Jetpack Compose提供了扩展功能,使其不必像 Android View 一样打开模拟器或连接到设备即可预览,从而加快了开发者实现其界面设计的迭代过程。
同时,为了实现如需为 Jetpack Compose 的预览功能,需要我们在应用 build.gradle 文件中添加以下依赖项:
debugImplementation "androidx.compose.ui:ui-tooling:1.2.1"
implementation "androidx.compose.ui:ui-tooling-preview:1.2.1"
3.1 预览模式
3.1.1 可组合项预览
首先,我们打开新建的Jetpack Compose项目,MainActivity.kt的代码如下:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeDemosTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ComposeDemosTheme {
Greeting("Android")
}
}
在上面的代码中,setContent()不再是以前的传递一个View或者是layout,而是一个组合函数,也就是一个Compose组件。而带有@Composable的Kotlin函数就是就是一个Compose组件,一般为了跟普通函数区分,因此上面的Greeting和DefaultPreview 都是一个Compose组件。
最后,点击拆分(设计/代码)视图,打开显示预览的右侧面板就可以看到效果。
@Preview接受参数来支持Android Studio呈现的方式,我们可以在代码中手动添加这些参数,也可以点击 @Preview 旁边的边线图标来显示配置选择器,以便选择和更改这些配置参数。
除此之外,Android Studio 提供了一些功能来扩展可组合项预览。我们可以通过读取 LocalInspectionMode CompositionLocal来确认可组合项是否正在预览中呈现。如果可组合项在预览中呈现,LocalInspectionMode.current 的结果为 true。
if (LocalInspectionMode.current) {
//呈现在预览界面
Text("Hello preview user!")
} else {
//在App中呈现
Text("Hello $name!")
}
3.1.2 互动模式
互动模式,可以实现在设备上互动的方式和预览互动,互动模式被隔离在沙盒环境中,在该模式下,我们可以在预览中点击元素并输入用户输入;预览甚至播放动画。预览互动模式可以直接在Android Studio中运行,由于并未运行模拟器,所以存在一些使用限制:
- 无法访问网络
- 无法访问文件
- 有些 Context API 不一定完全可用
使用互动模式时,只需要编写好代码,然后点击【Start interactive mode】开启,如下图。
3.1.3 部署预览
我们可以使用 @Preview 来部署应用到模拟器或实体设备上。点击 @Preview 注解旁边或预览顶部的 Deploy to Device 图标 ,Android Studio 会将该 @Preview 部署到连接的设备或模拟器上。
3.1.4 Multipreview
使用 Multipreview注解时,我们可以定义一个注解类,该类本身可配置多个采用不同配置的 Preview注解。将此注解添加到一个可组合函数后,系统会自动同时呈现所有不同的预览。例如,我们可以定义一个同时支持预览多个设备、字体大小或主题的注解类。
比如,我们首先定义一个可以改变字体的FontScalePreviews类。
@Preview(
name = "small font",
group = "font scales",
fontScale = 0.5f
)
@Preview(
name = "large font",
group = "font scales",
fontScale = 1.5f
)
annotation class FontScalePreviews
然后,在字体中使用这个预览可组合项使用此自定义注解。
@FontScalePreviews
@Composable
fun HelloWorldPreview() {
Text("Hello World")
}
最终的效果如下图。
当然,我们也可以将多个 MultiPreview 注解和普通 preview 注解结合进行使用,从而创建一个更完整的预览集。结合使用 MultiPreview 注解并不意味着所有不同的组合都会得以呈现。实际上,每个 MultiPreview 注解会独立运行,并且仅会呈现自己的变体。
@Preview(
name = "dark theme",
group = "themes",
uiMode = UI_MODE_NIGHT_YES
)
@FontScalePreviews
@DevicePreviews
annotation class CombinedPreviews
@CombinedPreviews
@Composable
fun HelloWorldPreview() {
MyTheme { Surface { Text("Hello world") } }
}
通过右键点击呈现的每个预览,即可将其作为图像来复制。
默认情况下,我们的可组合项是以透明背景来显示的。如果需要添加背景,那么需要用到showBackground 和 backgroundColor 两个参数,比如:
@Preview(showBackground = true, backgroundColor = 0xFF00FF00)
@Composable
fun WithGreenBackground() {
Text("Hello World")
}
如需手动设置尺寸,可以添加 heightDp 和 widthDp 参数。
@Preview(widthDp = 50, heightDp = 50)
@Composable
fun SquareComposablePreview() {
Box(Modifier.background(Color.Yellow)) {
Text("Hello World")
}
}
有时候,我们需要对状态栏和操作栏进行一些修改,那么可以使用showSystemUi参数。
@Preview(showSystemUi = true)
@Composable
fun DecoratedComposablePreview() {
Text("Hello World")
}
当然,我们也可以使用@PreviewParameter注解来添加参数,用来将示例数据传递给某个可组合项预览函数。
@Preview
@Composable
fun UserProfilePreview(
@PreviewParameter(UserPreviewParameterProvider::class) user: User
) {
UserProfile(user)
}
然后,创建一个可实现 PreviewParameterProvider 并以序列形式返回示例数据的类。
class UserPreviewParameterProvider : PreviewParameterProvider<User> {
override val values = sequenceOf(
User("Elise"),
User("Frank"),
User("Julia")
)
}
接着,序列中的每个数据元素都会呈现一个预览。
当需要为多个预览使用相同的提供程序类时。如有必要,可通过设置 limit 参数来限制呈现的预览数量,比如。
@Preview
@Composable
fun UserProfilePreview(
@PreviewParameter(UserPreviewParameterProvider::class, limit = 2) user: User
) {
UserProfile(user)
}
3.2 编辑器
为了提高使用 Jetpack Compose 时的工作效率,Android Studio在编辑器区域提供了一些功能,如实时模板、边线图标、颜色选择器等。
3.2.1 实时模板
Android Studio 提供了Compose 相关的实时模板,开发者可以通过输入相应的模板缩写来输入代码段,以实现快速插入。
- comp:用于设置 @Composable 函数
- prev:用于创建 @Preview 可组合函数
- paddp:用于以 dp 为单位添加 padding 修饰符
- weight:用于添加 weight 修饰符
- W、WR、WC:用于通过 Box、Row 或 Column 容器设置当前可组合项的呈现效果
3.2.2 边线图标
边线图标是边栏中可见的上下文操作,位于行号旁边。Android Studio 引入了多个 Jetpack Compose 专用边线图标,以便开发者更轻松地使用。比如,可以直接通过边线图标将 @Preview 部署到模拟器或实体设备上。
而对于颜色选择器来说,我们可以点击颜色,然后更改选中的眼神,如下所示。
为了方便对图像进行选择,Android Studio也支持图形选择器,可以通过图像资源选择器更改选择图片,如下所示:
3.3 迭代开发
作为移动开发者,移动应用界面开发并不是一次性开发完所有的内容的。Android Studio 通过提供不需要完整 build 即可检查、修改值和验证最终结果的工具,支持使用 Jetpack Compose 进行逐步开发。
3.3.1 实时修改字面量
Android Studio 可以实时更新在预览、模拟器和实体设备中的可组合项中使用的一些常量字面量,如Int、String、Color、Dp、Boolean等。
通过“Live Edit of Literals”界面指示器启用字面量修饰功能,无需进行编译即可查看触发实时更新的常量字面量。
3.3.2 实时编辑
我们可以打开 Android Studio Electric Eel 的 Canary 版本,然后使用实时编辑功能加快 Compose 开发过程。相较于实时编辑字面量功能,“实时编辑”是具备更强大功能的版本。开发者可以自动将代码更改部署到模拟器或设备上,从而实时查看可组合项更新后的效果。
3.3.3 Apply Changes
Apply Changes 支持更新代码和资源,并且不需要在模拟器或实体设备上重新运行代码。每当开发者添加、修改或删除可组合项时,只需要点击一下此按钮,即可更新应用,而不必重新部署。
3.4 布局检查器
通过布局检查器,开发者可以在模拟器或实体设备上检查正在运行的应用中的 Compose 布局。
如需跟踪重组,需要在视图选项中启用【Show Recomposition Counts】。
启用后,布局检查器会在左侧显示重组次数,在右侧显示跳过重组的次数。
3.5 动画
Android Studio 允许开发者从动画预览中检查动画,我们可以在组合项预览中描述了动画效果,检查每个动画值在给定时间点的确切值,并且可以暂停、循环播放、快进或放慢动画,以便在动画过渡过程中调试动画。
当然,我们也可以使用动画预览以图形方式呈现动画曲线,这对于确保正确编排动画值非常有用。
四、Kotlin与Jetpack Compose配合使用
Jetpack Compose使用Kotlin构建而成,在某些情况下,Kotlin 提供了一些特殊的惯用语,可以帮助开发者编写良好的 Compose 代码。如果使用另一种编程语言,那么很可能会错失 Compose 的一些优势。
4.1 默认参数
编写 Kotlin 函数时,我们可以指定函数参数的默认值;如果调用方未明确传递相应的值,系统就会使用这些默认值。在 Kotlin 中,编写一个函数并指定参数的默认值的方式和Java是类似的。
fun drawSquare(
sideLength: Int,
thickness: Int = 2,
edgeColor: Color = Color.Black
) { ... }
当然,上面的代码也可以简写成下面的方式,Kotlin的编译器也是可以识别的。
drawSquare(sideLength = 30, thickness = 5, edgeColor = Color.Red)
4.2 高阶函数和 lambda 表达式
所谓高阶函数,指的是接收其他函数作为参数的函数,Kotlin也是支持高阶函数的。例如,Button 可组合函数提供了一个 onClick lambda 参数。
Button(
// ...
onClick = myClickFunction
)
高阶函数与 lambda 表达式是自然配对的。如果您只需要使用该函数一次,则不必在其他位置进行定义以将其传递给高阶函数,而只需使用 lambda 表达式在该位置定义该函数即可。
Button(
// ...
onClick = {
// do something
// do something else
}
) { /* ... */ }
4.3 委托属性
Kotlin支持委托属性,这些属性可以像字段一样被调用,但它们的值是通过对表达式动态确定的。
``` class DelegatingClass { var name: String by nameGetterFunction() }
val myDC = DelegatingClass() println("The name property is: " + myDC.name) ```
当执行 println() 函数时,系统会调用 nameGetterFunction() 以返回字符串的值。同时,使用状态支持的属性时,这些委托属性特别有用。
var showDialog by remember { mutableStateOf(false) }
// Updating the var automatically triggers a state change
showDialog = true
4.4 协程
在 Kotlin 中,协程在语言级别提供了异步编程的支持。协程可以挂起执行,而不会阻塞线程。自适应界面本质上是异步的,而 Jetpack Compose 会在 API 级别引入协程而非使用回调来解决此问题。
Jetpack Compose 提供了可在界面层中安全使用协程的 API,rememberCoroutineScope 函数会返回一个 CoroutineScope,可以用它在事件处理脚本中创建协程并调用 Compose Suspend API。
val composableScope = rememberCoroutineScope()
Button(
// ...
onClick = {
composableScope.launch {
scrollState.animateScrollTo(0) // This is a suspend function
viewModel.loadData()
}
}
) { /* ... */ }
默认情况下,协程会依序执行代码块。正在运行且调用挂起函数的协程会挂起其执行,直到挂起函数返回,即使挂起函数将执行移至其他 CoroutineDispatcher,也是如此。若要同时执行代码,则需要创建新的协程。在上述示例中,如需在滚动到屏幕顶部的同时从 viewModel 加载数据,则需要两个协程。
val composableScope = rememberCoroutineScope()
Button(
onClick = {
composableScope.launch {
scrollState.animateScrollTo(0)
}
composableScope.launch {
viewModel.loadData()
}
}
) { /* ... */ }
协程可帮助您更轻松地合并异步 API。在以下示例中,我们会将 pointerInput 修饰符与动画 API 结合,以便在用户点按屏幕时在元素的位置呈现动画效果。
@Composable
fun MoveBoxWhereTapped() {
// Creates an `Animatable` to animate Offset and `remember` it.
val animatedOffset = remember {
Animatable(Offset(0f, 0f), Offset.VectorConverter)
}
Box(
// The pointerInput modifier takes a suspend block of code
Modifier.fillMaxSize().pointerInput(Unit) {
// Create a new CoroutineScope to be able to create new
// coroutines inside a suspend function
coroutineScope {
while (true) {
// Wait for the user to tap on the screen
val offset = awaitPointerEventScope {
awaitFirstDown().position
}
// Launch a new coroutine to asynchronously animate to where
// the user tapped on the screen
launch {
// Animate to the pressed position
animatedOffset.animateTo(offset)
}
}
}
}
) {
Text("Tap anywhere", Modifier.align(Alignment.Center))
Box(
Modifier
.offset {
// Use the animated offset as the offset of this Box
IntOffset(
animatedOffset.value.x.roundToInt(),
animatedOffset.value.y.roundToInt()
)
}
.size(40.dp)
.background(Color(0xff3c1361), CircleShape)
)
}
}
- Spring Boot 快速接入 ChatGPT
- 基于OpenAI API构建图片生成器
- 超详细的ChatGPT注册教程来了
- Android桌面图标快捷方式
- 推荐20个开源的前端低代码项目
- 轻量级的搜索引擎MeiliSearch
- Android Jetpack Compose快速上手
- Android 13 正式版发布
- 最新版React Native环境搭建
- 腾讯开源垃圾清理软件柠檬 Lemon
- RxDogTag:自动标记RxJava原始订阅点
- 2021,字节最值得关注的10个开源项目
- Google Colab 在线机器学习平台使用教程
- 前端如何开始深度学习,那不妨试试JAX
- 高仿京东Android App,集成React-Native热更功能
- 一文读懂Kotlin的数据流
- Android动态更换应用图标
- HTTP 3规范正式发布
- 基于Linphone开发Android音视频通话
- 走进WWDC 2022苹果开发者大会