Bootstrap

Jetpack Compose之LazyCoumn - 类似RecyclerView

LazyCoumn是一个类似ListViewRecyclerView的View,LazyColumn仅会呈现屏幕上的可见项目,从而在呈现大列表时提高性能。它可以添加单个item或者传入数据集合,添加多个Item,它的使用方法很简单,不需要像原来一样使用Adapter

//定义数据集合
val itemsList = (0..20).toList()
val itemsIndexedList = listOf("A", "B", "C")

LazyColumn {
    //添加多个item,回调中没有数据的下标
    items(itemsList) {
        Text("第$it 个Item")
    }
    //添加单个item
    item {
        Text("单个 item")
    }
    //添加多个Item,可以获取到数据的下标
    itemsIndexed(itemsIndexedList) { index, item ->
        Text("第$index 个Item,value = $item")
    }
}

效果:

在这里插入图片描述


itemitems函数接收的是一个**LazyListScope.()**DSL,所以我们可以自己定义LazyColumn item的内容。

以下内容特别注意!!!

注意:如果想要实现list add或者remove后UI也刷新,需要使用mutableStateListOf或者mutableStateMapOf来创建list集合

mutableStateListOf或者mutableStateMapOf只能通知添加/删除/替换这几个事件,所以如果更改了数据中的某个字段时,不会触发Recompose,可以使用替换来实现,如:list[index] = list [index].copy(name = "newName")

以上的内容非常重要!!!

contentPadding

contentPadding可以设置LazyColumn的边距:

val itemsList = (0..50).toList()
val itemsIndexedList = listOf("A", "B", "C")

LazyColumn(contentPadding = PaddingValues(horizontal = 20.dp, vertical = 20.dp)) {
    items(itemsList) {
        Text("第$it 个Item")
    }
    item {
        Text("单个 item")
    }
    itemsIndexed(itemsIndexedList) { index, item ->
        Text("第$index 个Item,value = $item")
    }
}

contentPadding接收一个PaddingValues类型的参数,horizontal设置的是左右边距,vertical设置的是上下边距,注意设置的是LazyColumn的边距,而不是里面item的边距。

verticalArrangement

verticalArrangement参数可以设置LazyColumn垂直排列的方式,其实使用方式和Column效果一致。这里还可以使用它来设置item的间距:

val itemsList = (0..10).toList()
val itemsIndexedList = listOf("A", "B", "C")

LazyColumn(Modifier.fillMaxHeight(),
           contentPadding = PaddingValues(horizontal = 20.dp, vertical = 20.dp),
           //设置item的间距为10dp 
           verticalArrangement  = Arrangement.spacedBy(10.dp)) {
    items(itemsList) {
        Text("第$it 个Item")
    }
    item {
        Text("单个 item")
    }
    itemsIndexed(itemsIndexedList) { index, item ->
        Text("第$index 个Item,value = $item")
    }
}

verticalArrangement = Arrangement.spacedBy(10.dp)用来设置item之间的间距。

horizontalAlignment

horizontalAlignment的使用方式和Column一样:Column horizontalAlignment

reverseLayout

reverseLayout参数可以改变LazyColumn的布局方向:
true 从上到下,默认的;
false 从下到上,第一个item会显示在最下方;

val itemsList = (0..10).toList()
val itemsIndexedList = listOf("A", "B", "C")

LazyColumn(
    Modifier.fillMaxHeight(),
    reverseLayout = true,
    verticalArrangement = Arrangement.spacedBy(10.dp)
) {
    items(itemsList) {
        Text("第$it 个Item")
    }
    item {
        Text("单个 item")
    }
    itemsIndexed(itemsIndexedList) { index, item ->
        Text("第$index 个Item,value = $item")
    }
}

效果:
在这里插入图片描述

stickyHeader

stickyHeader是实验性的API,不稳定也有可能被移除。它可以实现类似吸顶的效果:

val itemsList = (0..30).toList()
val itemsIndexedList = listOf("A", "B", "C")

LazyColumn(
    Modifier.fillMaxHeight().fillMaxWidth(),
    verticalArrangement = Arrangement.spacedBy(10.dp)
) {
    itemsIndexed(itemsIndexedList) { index, item ->
        Text("第$index 个Item,value = $item")
    }
    //滑动到这个item时,这个item会悬浮到顶部不动
    stickyHeader {
        Text("我是Title",modifier = Modifier.fillMaxWidth().background(Color.Red))
    }
    items(itemsList) {
        Text("第$it 个Item")
    }
    item {
        Text("单个 item")
    }

}

效果:

在这里插入图片描述

state

state参数可以设置一个LazyListState,用来监听滚动:

//创建LazyListState
val listState = rememberLazyListState()

val itemsList = (0..30).toList()
val itemsIndexedList = listOf("A", "B", "C")
Column() {
    Text(
        if (listState.firstVisibleItemIndex < 10) "前10个" else "后10个",
        color = Color.Red
    )
    LazyColumn(
        //设置LazyListState
        state = listState,
        verticalArrangement = Arrangement.spacedBy(10.dp)
    ) {
        items(itemsList) {
            Text("第$it 个Item")
        }
        itemsIndexed(itemsIndexedList) { index, item ->
            Text("第$index 个Item,value = $item")
        }
    }
}

上面的代码会在LazyColumn滚动到第10个item的时候,把最上方的Text文本改成"后10个"

在这里插入图片描述

listState.firstVisibleItemIndex 获取当前LazyColumn显示的第一个item的下标;
listState.firstVisibleItemScrollOffset获取当前LazyColumn显示的第一个item的偏移量;

滚动

listState还可以让LazyColumn滚动到指定的位置:

	//创建LazyListState
    val listState = rememberLazyListState()
    //创建CoroutineScope
    val coroutineScope = rememberCoroutineScope()

    val itemsList = (0..30).toList()
    val itemsIndexedList = listOf("A", "B", "C")
    Column() {
        Button(onClick = {
            coroutineScope.launch {
                listState.scrollToItem(5)
            }
        }) {
            Text(text = "直接滚动")
        }
        Button(onClick = {
            coroutineScope.launch {
                listState.animateScrollToItem(10)
            }
        }) {
            Text(text = "带滚动动画")
        }
        Text(
            if (listState.firstVisibleItemIndex < 10) "前10个" else "后10个",
            color = Color.Red
        )
        LazyColumn(
            //设置LazyListState
            state = listState,
            verticalArrangement = Arrangement.spacedBy(10.dp)
        ) {
            items(itemsList) {
                Text("第$it 个Item")
            }
            itemsIndexed(itemsIndexedList) { index, item ->
                Text("第$index 个Item,value = $item")
            }
        }
    }

listState.scrollToItem(5) 直接滚动到指定item的位置,不会有滚动过程的动画listState.animateScrollToItem(10) 滚动到指定item的位置,会有滚动动画

注意:listState.scrollToItem(5)listState.animateScrollToItem(10)方法都是suspend挂起函数,所以需要放到协程中执行。

;