一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情。
一、为什么要学 Jetpack Compose?
解决这个问题之前,我给自己找了几个理由:
- Compose使用声明式UI构建整个页面,像跨平台的Flutter、IOS的SwiftUI、鸿蒙的ArkUI,这些都是声明式UI,可见声明式UI已经是移动开发未来的大趋势了。
- Compose抛弃了传统的界面绘制机制,引入了固有特性测量(Intrinsic Measurement),这使得界面在绘制时不会多次测量同一个控件,因此界面绘制速度将会大大加快,在一些复杂的页面或控件中效果尤其明显。
- Compose整个系统都是严格按照 Material Design 进行设计的,利用 MaterialTheme 可以让我们更加方法地进行主题管理,甚至是主题切换。
- 基于Compose的UI界面,其数据信任单一来源,使得UI的展示与真实数据能够更好地做到统一。
- Android Studio 4.0 以上的编辑器,有着强大的工具,并且Compose使用的是 Kotlin Api,使得代码量被大幅度地减少,开发速度将会变得更快。
- Compose作为Jetpack全家桶的一员,为什么不学呢?
二、从Google官网入手
1、先来看看Compose首页上的宣传图
短短几行代码,就实现了这样的界面效果,看着就让人心动!
2、再来看看官方提供的代码
google先后提供了如下两种写法: 第一种:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text("Hello world!")
}
}
}
第二种:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MessageCard("world")
}
}
}
@Composable
fun MessageCard(name: String) {
Text(text = "Hello $name!")
}
运行起来的效果就是这样一个居于页面左上角的文本,此处有几点需要注意:
- 我们的Activity需要继承自ComponentActivity,注意是
androidx.activity.ComponentActivity
,不是androidx.core.app.ComponentActivity
,前者并不是一个Activity这么简单,有时间的话可以去看一下源码。 setContent{}
函数里面,定义的就是我们的布局,类似于传统写法中的setContentView(R.layout.main)
。- 第二种写法中的
MessageCard
函数带有@Compose
注解,表示这是一个可组合函数(也就是我们的布局所需要的组件),并且所有的可组合函数都必须带有此注解。
三、自己动手开干
我这里选择的是 Android Studio Bumblebee。在这个版本的AS下,我们可以做到:
- New Project 的时候,可以直接创建一个基于Compose的工程项目。
- 支持对Compose界面的实时预览,并且可以通过
Start Interactive Mode
,在预览界面上进行一些简单的交互测试。
创建功能
build.gradle配置
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 31
defaultConfig {
...
minSdk 21
}
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
}
...
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.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.1'
testImplementation 'junit:junit:4.13.2'
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"
}
这里有几个需要注意的问题:
- 要使用Compose,必须得支持Kotlin。并且,如果你使用的compose版本是1.0.5版本的话,Kotlin的版本需要使用1.5.31或更高;如果你使用compose的1.1.1版本,则需要Kotlin版本1.6.10或更高。PS:我这里使用的是compose1.0.5 + kotlin1.5.31
- minSdk最小需要支持到Api21
- 需要将Java和Kotlin的编辑器目标设置为Java8
- 需要打开compose的
enable
开关
接下来,在dependencies
中,我们可以看到几个关键的库:
implementation "androidx.compose.ui:ui:$compose_version"
// 主题
implementation "androidx.compose.material:material:$compose_version"
implementation 'androidx.activity:activity-compose:1.3.1'
// 工具支持
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
接下来,利用Compose提供的组件实现一个简单的页面
代码如下:
@Composable
fun BasicWidget() {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
//文字
Text(text = "这是一个文字",
modifier = Modifier.clickable { showShort("这是一个Text") })
//图片
Image(painter = painterResource(id = R.drawable.panda),
contentDescription = null,
modifier = Modifier.clickable { showShort("这是一个Image") })
//图标
Icon(painter = painterResource(id = R.drawable.panda),
contentDescription = null,
modifier = Modifier.clickable { showShort("这是一个Icon") })
//按钮
Button(onClick = { showShort("这是一个Button") }) {}
//开关
val switchState = remember { mutableStateOf(true) }
Switch(checked = switchState.value, onCheckedChange = {
switchState.value = it
showShort("开关:$it")
})
//单选框
val selectedState = remember { mutableStateOf(false) }
RadioButton(selected = selectedState.value, onClick = {
selectedState.value = selectedState.value.not()
showShort("单选框:${selectedState.value}")
})
//复选框
val checkState = remember { mutableStateOf(false) }
Checkbox(checked = checkState.value, onCheckedChange = {
checkState.value = it
showShort("复选框:${it}")
})
}
}