Compose的列表(七)
一、前言
之前介绍过可以使用Column
和Row
来进行列表排列。只是如果我们需要显示大量的列表时候或者对列表进行复杂的操作时候,使用Column
和Row
会有严重的性能问题,这时候就需要使用延迟列表 LazyColumn
或者LazyRow
会更好一点。另外官方还提供了网格布局LazyVerticalGrid(这是一个实验性功能,后期可能会被删掉),这里就不进行另行说明。因为 LazyColumn
或者LazyRow
的API基本上相似,所以本篇只演示一种
二、LazyColumn
LazyColumn
的使用方式要比RecycleView
简单一点。这里演示如何创建一个最简单的列表
LazyColumn {
// Add a single item
item {//添加一个
Text(text = "First item")
}
// Add 5 items
// 添加多个
items(5) { index ->
Text(text = "Item: $index")
}
// Add another single item
item {
Text(text = "Last item")
}
}
但是实际上列表数量是一个数组,针对这种情况可以使用以下方式
@Composable
fun messageList(messages: List<String>) {// 值可以是 List或者Array两种方式
LazyColumn {
// items(messages.size) { message ->//遍历索引的方式
// Text(text = messages[message])
// }
// items(items = messages){ message -> //遍历内容
// Text(text = message)
// }
itemsIndexed(items = messages){ index, item -> //遍历内容和索引
Text(text = "索引:$index -- 内容:$item")
}
}
}
三、列表修饰
只是简单的显示列表并不能满足实际需求,因此可以根据LazyColumn
所包含的修饰符来添加一些修饰,这里以添加内边距为例
LazyColumn(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
) {
// ...
}
四、动画
暂时列表还没有动画功能
五、监听滚动位置
有时候会对列表滚动进行监听,这里可以使用LazyListState
来进行处理,范式如下:
@Composable
fun MessageList(messages: List<Message>) {
// Remember our own LazyListState
val listState = rememberLazyListState()
// Provide it to LazyColumn
LazyColumn(state = listState) {
// ...
}
}
假如我们想要根据是否滚动到第一项来判断是否显示按钮,可以使用firstVisibleItemIndex
和 firstVisibleItemScrollOffset
来进行判断
@OptIn(ExperimentalAnimationApi::class) // AnimatedVisibility
@Composable
fun MessageList(messages: List<Message>) {
Box {
val listState = rememberLazyListState()
LazyColumn(state = listState) {
// ...
}
// Show the button if the first visible item is past
// the first item. We use a remembered derived state to
// minimize unnecessary compositions
val showButton by remember {
derivedStateOf {
listState.firstVisibleItemIndex > 0
}
}
AnimatedVisibility(visible = showButton) {
ScrollToTopButton()
}
}
}
如果我们需要人为的控制滚动位置,可以使用scrollToItem()
和animateScrollToItem()
来进行处理,不过这两个函数使用了协程,因此需要使用时候需要参考以下方式
@Composable
fun MessageList(messages: List<Message>) {
val listState = rememberLazyListState()
// Remember a CoroutineScope to be able to launch
val coroutineScope = rememberCoroutineScope()
LazyColumn(state = listState) {
// ...
}
ScrollToTopButton(
onClick = {
coroutineScope.launch {
// Animate scroll to the first item
listState.animateScrollToItem(index = 0)
}
}
)
}
六、Key
默认情况下列表项的状态是和位置绑定的,倘若数据集发生更改,那么状态就会丢失,从而可能出现数据混乱的情况。所以这里需要使用Key来进行状态保存
@Composable
fun MessageList(messages: List<Message>) {
LazyColumn {
items(
items = messages,
key = { message ->
// Return a stable + unique key for the item
message.id
}
) { message ->
MessageRow(message)
}
}
}
七、数据的更改
上文中在列表创建完后数据就不会再更改,这里可以使用remember
来进行数据的修改、添加、移除,修改完的程序如下
@Composable
fun constrainLayout(){
ConstraintLayout {
// Create references for the composables to constrain
val (button, text, list ) = createRefs()
// val data = mutableListOf("a","b","c")
val data = remember { mutableStateListOf<String>("a","b","c") }
// val data = mutableStateListOf("a","b","c") 这种方式也可以,但是这样会导致每次重组有不同的状态,而remember因为缓存的原因却不会,详情可以了解Compose中的状态
Button(
onClick = {
data.add("d")
},
// Assign reference "button" to the Button composable
// and constrain it to the top of the ConstraintLayout
modifier = Modifier.constrainAs(button) {
top.linkTo(parent.top, margin = 16.dp)
}
) {
Text("Button")
}
// Assign reference "text" to the Text composable
// and constrain it to the bottom of the Button composable
Text("Text", Modifier.constrainAs(text) {
top.linkTo(button.bottom, margin = 16.dp)
})
messageList(data,Modifier.constrainAs(list) {
top.linkTo(text.bottom, margin = 16.dp)
})
}
}
@Composable
fun messageList(messages: List<String>,modifier: Modifier) {// 值可以是 List或者Array两种方式
LazyColumn(modifier) {
// items(messages.size) { message ->//遍历索引的方式
// Text(text = messages[message])
// }
// items(items = messages){ message -> //遍历内容
// Text(text = message)
// }
itemsIndexed(items = messages){ index, item -> //遍历内容和索引
Text(text = "索引:$index -- 内容:$item")
}
}
}
关于为什么使用mutableStateListOf
来进行修改数据,官方的原文如下:
注意:在 Compose 中将可变对象(如 ArrayList<T>
或 mutableListOf()
)用作状态会导致用户在您的应用中看到不正确或陈旧的数据。
不可观察的可变对象(如 ArrayList<T>
或可变数据类)不能由 Compose 观察,因而 Compose 不能在它们发生变化时触发重组。
我们建议您使用可观察的数据存储器(如 State<List<T>>
)和不可变的 listOf()
,而不是使用不可观察的可变对象。
该段源自于以下链接:
https://developer.android.google.cn/jetpack/compose/state?hl=zh-cn
八、参考链接
- Lazy
- 列表
https://developer.android.google.cn/jetpack/compose/lists
- 状态
https://developer.android.google.cn/jetpack/compose/state
- snapshots
- snapshotFlow(演示了如何更改一个定义好的Compose内容)
- mutableStateListOf
- Compose基础
https://developer.android.google.cn/codelabs/jetpack-compose-basics#4
更多推荐
所有评论(0)