前传
这就是一最最最入门级文章(无图片),开发环境需提前部署,还得先学Android基础知识,如果想学习的深还得专门看专门的教程,自己玩玩就算了
这篇文章学完后基本上你能掌握Compose的%65,真的只是写着好玩
Compose是什么?
Compose是Android官方新推出的一篇ui工具包,旨在提升ui编写速度,并使用声明式编程范式
Compose 一部曲 可组合项
Compose使用一个带Composable注解的大写首字母函数名作为基本ui单元,名叫 可组合项
@Composable
fun Home() { /* Compose UI */ }
放点ui?
setContent {
Home() // 显示Home可组合项
}
@Composable
fun Home() {
Text(text = "Hi Compose")
}
Compose 第二部曲 状态
状态总得来说应用于事件更新
比如这里有一个按钮,点击一下就将i加1
@Composable
fun Home() {
var i = 0
Button(onClick = { i++ }) {
Text(text = "Click Me Add 1, Count : $i")
}
}
可是你只要运行点击一下,就会发现并不会加1,为什么?
界面毕竟是死的,i加是加了可Text没反应过来,这时我们在i这里套一个mutableStateOf函数,mutableStateOf就会帮我们重新运行这个可组合项
但是运行到第一行,i就已经初始化为0了,那么这时我们再套一个remember让它帮我们恢复就完美解决了
var i by remember { mutableStateOf(0) }
这便是最Compose最6b的状态,反过头看View的findViewById和setText,是不是好用多了? 所以说万物更新皆为状态,但是呢,状态也不能放进内部可组合项
@Composable
fun MyScreen() {
Button(onClick = {
var count by remember { mutableStateOf(0) } // 每次重组重新创建
count++ // 不会保存
}) {
Text("点击")
}
}
Compose第三部曲 Material Design & 布局
Material Design也是Compose的灵魂所在,接下来就让我们看看吧
布局
布局分为
Column Row Box
也就是
垂直布局 水平布局 重叠布局
默认是Box重叠布局,比如我这里有个图片,我们将它裁剪成了圆(抱歉没有图片)
Image(
painter = painterResource(id = R.drawable.avatar), //图片资源
contentDescription = "头像", // 无障碍模式介绍
modifier = Modifier
.size(50.dp)
.clip(CircleShape), // 裁剪为圆形
contentScale = ContentScale.Crop // 裁剪填充
)
接下来,我们利用布局来做一个联系人列表
Row { //水平布局
Image(
painter = painterResource(id = R.drawable.avatar), //图片资源
contentDescription = "头像",
modifier = Modifier
.size(50.dp)
.clip(CircleShape), // 裁剪为圆形
contentScale = ContentScale.Crop // 裁剪填充
)
Column( // 垂直布局
modifier = Modifier
.padding(start = 8.dp) // 开头填充8dp
.align(Alignment.CenterVertically) // 垂直居中对齐
) {
Text(text = "Erqi")
Text(text = "Pupils write Android", style = MaterialTheme.typography.bodyMedium) // 中等大标题
}
}
Material Design单向数据流组件
单向数据流是什么?
Compose比较推崇使用单向数据流,从具体操作来看叫状态提升,就是将数据和事件交给外面的父容器管,这里我们不用容器保存,直接存储
@Composable
fun MyCounter(
count: Int, // 状态接收
onIncrement: () -> Unit // 事件回调
) {
Button(onClick = onIncrement) {
Text("Click Me Add1, Count : $coubt")
}
}
最后然后在setContent里传递参数,不用多说
单向数据流组件
单向数据流组件一个典型的例子就是输入框了,运行后可以自己康康
var email by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("email") },
leadingIcon = { Icon(Icons.Default.Email, null) }, // 前导图标
modifier = Modifier.fillMaxWidth()
)
Modifier修饰符
modifier用来修饰组件,属于Compose灵魂其二,几乎适用于所有组件,以下是几个小例子
fillMaxWidth将组件的宽度设置成最大fillMaxHeight将组件的高度设置成最大fillMaxSize将组件的大小设置成最大padding设置内间距clickable设置点击事件horizontalScroll(rememberScrollState())水平滚动verticalScroll(rememberScrollState())垂直滚动
当然,这里有个坑,
Modifier是链式调用,不同的顺序会有不同的效果
Modifier // 背景在内层
.padding(16.dp)
.background(Color.Red)
Modifier // 背景在外层
.background(Color.Red)
.padding(16.dp)
更多请见:developer.android.com/jetpack/com…
Compose五部曲 ViewModel容器集成
ViewModel是Jetpack库生命周期较长的容器,要使用这个容器需提前导入依赖
我们先写一个继承ViewModel的MyViewModel类
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
var count = 0 // 这是我们的状态
private set // 外部不能直接修改
fun increment() { // 这是事件
count++
}
}
然后在Compose里使用
setContent {
val myViewModel : MyViewModel = viewModel()
MyScreen(myViewModel)
}
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
Column {
Text("计数:${viewModel.count}") // 拎出值
Button(onClick = { viewModel.increment() }) {
Text("点击")
}
}
}
那么这就是ViewModel最基本的用法了,不过,我们还有StateFlow容器,配合ViewModel使用
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class MyViewModel : ViewModel() {
// 1. 创建可变StateFlow(下划线开头是惯例)
private val _count = MutableStateFlow(0)
// 2. 对外暴露不可变的StateFlow
val count: StateFlow<Int> = _count
// 3. 修改数据
fun increment() {
_count.value++ // 直接改value
}
}
Compose用法
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
// 4. collectAsState() 把StateFlow转成Compose状态
val count by viewModel.count.collectAsState()
Text("数值:$count")
Button(onClick = { viewModel.increment() }) {
Text("增加")
}
}
总结:MutableStateFlow 存数据,StateFlow 读数据,.collectAsState() 用数据
后传
后什么转,自己再去学这些,你就相当于完全掌握了
动画API页面导航副作用Material Design的主题