一、初探
1、什么是 Compose
Jetpack Compose 谷歌推出的 UI 开发框架,目的是简化界面开发,无需在 XML 中定义 UI。Compose 将响应式编程模型与简洁易用的 Kotlin 编程语言相结合,并采用完全声明式的代码编写方式,通过调用一系列函数来描述界面,这些函数会将数据转换为 UI 层次结构。当底层数据发生变化时,Compose 框架会自动重新执行这些函数,从而更新 UI。
总结来说,Android Compose 是一种“现代化”的 UI 开发框架,它通过声明式编程、可组合性、高效的状态管理和动画支持等特性,极大地简化了 Android 应用的界面开发工作,提升了代码质量和开发效率。
2、Hello Compose
创建项目
点击 Empty Activity 创建新项目,在 Android Studio 2023.1.1 版本,默认创建的项目就是基于 Compose,所以可以直接拿来进行使用。
运行项目
官方 demo 实现的效果非常简单,就是一句 Hello Compose! ,接下来我们简单看一下代码是如何实现的。
查看代码
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// 应用主题
ComposeDemoTheme {
// 一个通用的布局容修饰或扩充可组合项器,可以设置背景色、形状
Surface(
// 修饰或扩充可组合项
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Compose")
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ComposeDemoTheme {
Greeting("Android")
}
}
二、再探
1、理解“组合”和“预览”
在我们正式实战之前,需要了解两个注解。
1)@Composable
@Composable 注解用于标记一个函数可以被 Compose 编译器用来构建 UI,这些函数被称为 Composable 函数,具有以下特点:
- 可组合:Composable 函数可以调用其他 Composable 函数,这样可以组合多个 UI 组件来构建复杂的 UI。
- 可重用:Composable 函数可以被多次调用,每次调用都会生成 UI 的一个独立实例。
- 响应式:Composable 函数可以响应状态的变化,当状态变化时,只有依赖于这个状态的 Composable 函数会被重新调用,并且更新 UI。
2)@Preview
@Preview注解用于在 Android Studio 的预览窗口中显示 Composable 函数的预览。当我们在 Composable 函数上添加 @Preview 注解时,Android Studio 会在设计模式下渲染该函数的 UI,并显示在预览窗口中。这样可以在不运行代码的情况下,直接对 UI 进行查看和检查,具体效果如下图所示。
2、基础组件
首先先带大家了解一下基础组件,以图文的形式进行示例。除了少部分控件与 Android 原生 View 有些许差异,大部分特性都是一样的。下面会依次介绍我们常用的控件,比较简单请放心食用。
名称 | 描述 |
---|---|
Text | 用于显示文本 |
Image | 用于显示图片 |
TextField | 文本输入控件 |
Button | 用于创建按钮 |
Checkbox | 复选框控件 |
RadioButton | 单选按钮控件 |
LinearProgressIndicator | 水平进度条控件 |
Slider | 滑块控件 |
1)Text
@Composable
fun MTextView(modifier: Modifier = Modifier) {
Text(
text = "Hello Text !",
fontSize = 36.sp,
color = Color(0xFF121113),
fontStyle = FontStyle.Italic,
modifier = modifier
)
}
2)Image
@Composable
fun ShowImage() {
val image = painterResource(R.drawable.ic_launcher)
Image(
painter = image,
contentDescription = "image",
modifier = Modifier.padding(16.dp),
contentScale = ContentScale.Crop,
alignment = Alignment.Center
)
}
3)TextField
@Composable
fun EditTextView() {
val text = remember { mutableStateOf("") }
TextField(
value = text.value,
onValueChange = { text.value = it },
//提示文本,当输入框为空时显示
placeholder = { Text("input user name", color = Color(0xFF666262)) },
singleLine = true,
maxLines = 1,
textStyle = TextStyle(color = Color(0xFF111111), fontSize = 28.sp),
)
}
4)Button
@Composable
fun ButtonView() {
val context = LocalContext.current
//创建一个协程
val scope = rememberCoroutineScope()
Button(onClick = {
scope.launch {
Toast.makeText(context, "This is Button", Toast.LENGTH_SHORT).show()
}
}, modifier = Modifier
.size(200.dp, 100.dp)
.padding(20.dp), enabled = true) {
Text("Click Me", fontSize = 20.sp)
}
}
5)Checkbox
@Composable
fun CheckboxView() {
// 保存状态
val state = remember { mutableStateOf(true) }
Checkbox(
checked = state.value,
onCheckedChange = { state.value = it }
)
}
6)RadioButton
@Composable
fun RadioButtonView() {
// 默认保存选择MVVM
val normal = remember { mutableStateOf("MVVM") }
val options = listOf("MVVM", "MVP", "MVI", "MVC")
Column {
options.forEach { option ->
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(
selected = normal.value == option,
onClick = { normal.value = option }
)
Text(
text = option,
modifier = Modifier.padding(start = 8.dp)
)
}
}
}
}
7)LinearProgressIndicator
@Composable
fun ProgressBarView() {
val progress = remember { mutableFloatStateOf(0.8f) }
LinearProgressIndicator(
progress = progress.floatValue,
modifier = Modifier.padding(16.dp),
//进度条颜色
color = Color.Red,
//背景颜色
trackColor = Color.Gray,
//进度条样式
strokeCap = StrokeCap.Round
)
}
8)Slider
@Composable
fun SliderView() {
val position = remember { mutableFloatStateOf(0.3f) }
Slider(
value = position.floatValue,
onValueChange = { newValue -> position.floatValue = newValue },
valueRange = 0f..100f,
modifier = Modifier.padding(16.dp),
colors = SliderDefaults.colors(
//滑块颜色
thumbColor = Color.Red,
//滑轨颜色
activeTrackColor = Color.Green,
//滑轨背景颜色
inactiveTrackColor = Color.Gray
)
)
}
3、布局组件
接下来给大家介绍一下常用布局组件的简单使用,也是以图文形式进行示例。
名称 | 描述 |
---|---|
Scaffold | 一个基础布局,通常包含顶部栏、底部栏和一个内容区域 |
Column | 垂直布局 |
Row | 水平布局 |
Surface | 一个通用的布局容器,可以设置背景色、形状等 |
Card | 卡片布局 |
LazyColumn | 懒加载的垂直滚动列表 |
LazyRow | 懒加载的水平滚动列表 |
1)Scaffold
class MainActivity : ComponentActivity() {
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Scaffold(
topBar = {
Text("Jetpack Compose", modifier = Modifier.padding(16.dp, 0.dp, 0.dp, 0.dp))
},
content = {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingPreview()
}
}
)
}
}
}
}
2)Column
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyApplicationTheme {
Column(
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
verticalArrangement = Arrangement.Center
) {
ButtonView()
ButtonView()
ButtonView()
ButtonView()
}
}
}
3)Row
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyApplicationTheme {
Row(
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
horizontalArrangement = Arrangement.Start
) {
ShowImage()
ShowImage()
ShowImage()
}
}
}
4)Surface
@Composable
fun SurfaceLayout() {
Surface(
color = Color.Blue,
modifier = Modifier
.padding(8.dp)
.size(300.dp, 200.dp)
) {
Text("This is Surface Layout", color = Color.White)
}
}
5)Card
@Composable
fun CardLayout() {
Card(
modifier = Modifier
.padding(8.dp)
.size(300.dp, 200.dp),
//设置圆角
shape = RoundedCornerShape(20.dp),
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
"This is Card Layout",
textAlign = TextAlign.Center,
color = Color.Black,
fontSize = 20.sp
)
}
}
}
6)LazyColumn
@Composable
fun LazyColumnLayout() {
val context = LocalContext.current
val items = mutableListOf<String>()
for (i in 0..50) {
items += "Item data $i"
}
//懒加载的列表,只有当item出现在屏幕上时才会加载
LazyColumn {
items(items) { item ->
Text(text = item, modifier = Modifier
.padding(16.dp)
.clickable {
Toast
.makeText(context, item, Toast.LENGTH_SHORT)
.show()
})
}
}
}
4、设计
1)主题和样式
//黑夜主题颜色
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
//白天主题颜色
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
)
@Composable
fun MyApplicationTheme(
//主题模式
darkTheme: Boolean = isSystemInDarkTheme(),
//是否动态颜色
dynamicColor: Boolean = true,
//布局
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
val Typography = Typography(
bodyLarge = TextStyle(
//字体样式
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)
2)动画
开启 animateFloatAsState 动画
@Composable
fun StartFloatAnimation() {
var started by remember { mutableStateOf(false) }
// 使用 animateFloatAsState 创建浮点数动画
val size by animateFloatAsState(
if (started) {
200f
} else {
100f
},
visibilityThreshold = 0.1f,
// 使用 keyframes 定义动画的持续时间
animationSpec = keyframes {
durationMillis = 1000
}, label = ""
)
Box(
modifier = Modifier
.size(size.dp)
.background(Color.Blue)
.clickable { started = !started } // 点击时切换大小
)
}
开启 animateTo 动画
@Composable
fun StartAnimationToColor() {
val color = remember { Animatable(Color.Red) }
// //创建一个协程
val scope = rememberCoroutineScope()
Box(modifier = Modifier
.size(240.dp)
.background(color.value)
.clickable {
// 开启协程
scope.launch {
// 改变动画到目标颜色
color.animateTo(
targetValue = Color.Blue,
animationSpec = tween(durationMillis = 5000, easing = LinearOutSlowInEasing)
)
}
}
)
}
三、总结
以上就是 Compose 的简单使用,帮助大家对 Compose 有个初步的认识和了解,如果想要了解更多,建议直接访问官网。从个人角度出发,对于 Android 开发者来讲 Compose 还是比较容易上手,特别是有 Flutter 开发经验会更比较容易接受和掌握。所以,对于 Compose 感兴趣的同学赶紧学起来吧!