Compose的列表(七)

文章目录

    • 一、前言
    • 二、LazyColumn
    • 三、列表修饰
    • 四、动画
    • 五、监听滚动位置
    • 六、Key
    • 七、数据的更改
    • 八、参考链接

一、前言

之前介绍过可以使用ColumnRow来进行列表排列。只是如果我们需要显示大量的列表时候或者对列表进行复杂的操作时候,使用ColumnRow会有严重的性能问题,这时候就需要使用延迟列表 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) {
        // ...
    }
}

假如我们想要根据是否滚动到第一项来判断是否显示按钮,可以使用firstVisibleItemIndexfirstVisibleItemScrollOffset来进行判断

@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 中将可变对象(如 ArrayListmutableListOf())用作状态会导致用户在您的应用中看到不正确或陈旧的数据。

不可观察的可变对象(如 ArrayList 或可变数据类)不能由 Compose 观察,因而 Compose 不能在它们发生变化时触发重组。

我们建议您使用可观察的数据存储器(如 State>)和不可变的 listOf(),而不是使用不可观察的可变对象。

该段源自于以下链接:

https://developer.android.google.cn/jetpack/compose/state?hl=zh-cn

八、参考链接

  1. Lazy

https://developer.android.google.cn/reference/kotlin/androidx/compose/foundation/lazy/package-summary

  1. 列表

https://developer.android.google.cn/jetpack/compose/lists

  1. 状态

https://developer.android.google.cn/jetpack/compose/state

  1. snapshots

https://developer.android.google.cn/reference/kotlin/androidx/compose/runtime/snapshots/package-summary

  1. snapshotFlow(演示了如何更改一个定义好的Compose内容)

https://developer.android.google.cn/reference/kotlin/androidx/compose/runtime/package-summary#snapshotFlow(kotlin.Function0)

  1. mutableStateListOf

https://developer.android.google.cn/reference/kotlin/androidx/compose/runtime/package-summary#mutableStateListOf()

  1. Compose基础

https://developer.android.google.cn/codelabs/jetpack-compose-basics#4

你可能感兴趣的:(JetPack)