Android的Compose概览
文章目录
Compose概览
官方文档
我个人看了下官方的文档,尝试了一下demo,大概做一个个人的理解和记录,还没有深入研究尝试
compose是什么
Android推出的新的,以声明式语言方式,用来进行UI编写的UI库
声明式
常见的是与命令式比较出现,我们以前的常用的是就是命令式语言编写的UI
看了一些介绍的文章,简单的一点理解就是:
命令式编程就像王刚教你做菜,会告诉你每一步做什么
声明式就是直接告诉王刚要吃什么菜,做菜的人是王刚
关于Compose的声明式UI,暂时能感受到的:
- 不用写xml文件了
- 直接调用compose的库就可以在界面渲染出组件
- 猜想这种编写方式以后会方便复用(比如我复用一个compose函数,比复用一个xml+java要简单吧)
声明式更新
扔物线视频
扔物线视频中提到,声明式的重点在于可以自动更新页面,而dataBinding更新的是页面的数据,使用compose的声明式可以更新页面的数据和其他属性,甚至是结构
组合函数
@compose注解的函数,注释告诉编译器,此函数旨在将数据转换为界面,用组合函数作为参数的时候,也要声明有@compose注解
组合函数可以调用其他的组合函数,不会返回任何内容
状态state
简单来说,就是会影响界面发生变化的变量
状态的变化会引起其所在compose函数重构
var value by remember { mutableStateOf(default) }
官方例子中的写法,还提到有其他写法:
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
mutableStateOf
创建一个可观察的状态变量,持有单一值。当这个变量变化的时候,会引起函数重组,相关部分界面重新渲染
remember
缓存了状态变量的值
rememberSaveable
这个是相对于remember的,当横竖屏切换的时候,使用remember是不能保存状态值的,使用rememberSaveable就可以
状态提升
这个没有理解清除,但是看代码的意思,是把状态部分抽出去进行了封装
未进行状态提升的时候
@Composable
fun HelloContent() {
Column(modifier = Modifier.padding(16.dp)) {
var name by remember { mutableStateOf("") }
if (name.isNotEmpty()) {
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
}
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Name") }
)
}
}
官方的例子:进行状态提升后
@Composable
fun HelloScreen() {
var name by rememberSaveable { mutableStateOf("") }
HelloContent(name = name, onNameChange = { name = it })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") }
)
}
}
如果按照之前的写法,那么name应该是在helloContent中的,我们直接调用helloContent,提升后,我们要调用helloScreen,这样做的好处,官方的总结:
以这种方式提升的状态具有一些重要的属性:
单一可信来源:我们会通过移动状态而不是复制状态,来确保只有一个可信来源。这有助于避免 bug。
封装:只有有状态可组合项能够修改其状态。这完全是内部的。
可共享:可与多个可组合项共享提升的状态。如果想在另一个可组合项中执行 name 操作,可以通过变量提升来做到这一点。
可拦截:无状态可组合项的调用方可以在更改状态之前决定忽略或修改事件。
解耦:无状态 ExpandingCard 的状态可以存储在任何位置。例如,现在可以将 name 移入 ViewModel。
个人理解,也就是这个状态可能影响多个部分,我们把状态封装后,统一状态,统一处理
接入ViewModel和LiveData使用
class HelloViewModel : ViewModel() {
// LiveData holds state which is observed by the UI
// (state flows down from ViewModel)
private val _name = MutableLiveData("")
val name: LiveData<String> = _name
// onNameChange is an event we're defining that the UI can invoke
// (events flow up from UI)
fun onNameChange(newName: String) {
_name.value = newName
}
}
@Composable
fun HelloScreen(helloViewModel: HelloViewModel = viewModel()) {
// by default, viewModel() follows the Lifecycle as the Activity or Fragment
// that calls HelloScreen(). This lifecycle can be modified by callers of HelloScreen.
// name is the current value of [helloViewModel.name]
// with an initial value of ""
val name: String by helloViewModel.name.observeAsState("")
HelloContent(name = name, onNameChange = { helloViewModel.onNameChange(it) })
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") }
)
}
}
很明显的,是替换掉了
remember { mutableStateOf(default) } 这种方式,以
ViewModel.name.observeAsState("") 方式实现
Modifier
官方文档和例子
修饰符,可以用来设置渲染的布局,尺寸等,修饰符声明的顺序很重要,因为是按顺序渲染的
推荐阅读