Android开发 Jetpack compose LazyColumn 与 LazyRow、LazyVerticalGrid、LazyHorizontalGrid、LazyVerticalStaggeredGrid

发布时间 2023-08-08 14:54:21作者: 观心静

前言

  此篇博客讲解LazyColumn 与 LazyRow、LazyVerticalGrid、LazyHorizontalGrid,在compose里LazyColumn与LazyRow与是用来延迟加载数据的,它对标原来xml里的ListView与RecyclerView。

LazyColumn 纵向列表

效果图

代码

@Composable
fun APage() {
    val listData = remember {
        //mutableStateListOf 这个很关键,需要动态新增数据一定需要使用mutableStateListOf
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
        )
    }
    Column {
        Button(modifier = Modifier.fillMaxWidth(), onClick = { listData.add("山竹" to R.mipmap.ic_fruit_mangosteen) }) {
            Text(text = "新增数据")
        }
        //LazyColumn
        LazyColumn(
            Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center
        ) {
            //这个items很关键,LazyColumn一定需要使用这个
            items(listData.size){
                Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(20.dp)) {
                    Image(painter = painterResource(id = listData[it].second), contentDescription = null, modifier = Modifier
                        .width(100.dp)
                        .height(100.dp))
                    Text(text = listData[it].first, fontSize = 25.sp, modifier = Modifier.padding(start = 80.dp))
                }
            }
        }
    }
}

LazyRow 横向列表

效果图

代码

@Composable
fun APage() {
    val listData = remember {
        //mutableStateListOf 这个很关键,需要动态新增数据一定需要使用mutableStateListOf
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
        )
    }
    Column {
        Button(modifier = Modifier.fillMaxWidth(), onClick = { listData.add("山竹" to R.mipmap.ic_fruit_mangosteen) }) {
            Text(text = "新增数据")
        }
        //LazyRow
        LazyRow(
            Modifier.fillMaxSize(),
        ) {
            //这个items很关键
            items(listData.size){
                Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(20.dp)) {
                    Image(painter = painterResource(id = listData[it].second), contentDescription = null, modifier = Modifier
                        .width(100.dp)
                        .height(100.dp))
                    Text(text = listData[it].first, fontSize = 25.sp)
                }
            }
        }
    }
}

LazyVerticalGrid 纵向宫格列表

效果图

代码

@Composable
fun APage() {
    val listData = remember {
        //mutableStateListOf 这个很关键,需要动态新增数据一定需要使用mutableStateListOf
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
            "橘子" to R.mipmap.ic_fruit_orange,
            "梨子" to R.mipmap.ic_fruit_pear,
        )
    }
    Column {
        Button(modifier = Modifier.fillMaxWidth(), onClick = { listData.add("山竹" to R.mipmap.ic_fruit_mangosteen) }) {
            Text(text = "新增数据")
        }
        //LazyVerticalGrid
        //columns 设置显示几列
        LazyVerticalGrid(columns = GridCells.Fixed(3)) {
            items(listData.size){
                Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(20.dp)) {
                    Image(painter = painterResource(id = listData[it].second), contentDescription = null, modifier = Modifier
                        .width(90.dp)
                        .height(90.dp))
                    Text(text = listData[it].first, fontSize = 18.sp)
                }
            }
        }
    }
}

LazyHorizontalGrid横向宫格列表

效果图

代码

@Composable
fun APage() {
    val listData = remember {
        //mutableStateListOf 这个很关键,需要动态新增数据一定需要使用mutableStateListOf
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
            "橘子" to R.mipmap.ic_fruit_orange,
            "梨子" to R.mipmap.ic_fruit_pear,
        )
    }
    Column {
        Button(modifier = Modifier.fillMaxWidth(), onClick = { listData.add("山竹" to R.mipmap.ic_fruit_mangosteen) }) {
            Text(text = "新增数据")
        }
        //LazyHorizontalGrid
        //rows 设置显示几行
        LazyHorizontalGrid(rows = GridCells.Fixed(4)) {
            items(listData.size){
                Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(20.dp)) {
                    Image(painter = painterResource(id = listData[it].second), contentDescription = null, modifier = Modifier
                        .width(90.dp)
                        .height(90.dp))
                    Text(text = listData[it].first, fontSize = 18.sp)
                }
            }
        }
    }
}

LazyVerticalStaggeredGrid 纵向瀑布列表

请注意!LazyVerticalStaggeredGrid为实验性API,并且Compose版本需要1.4.0以上。 这个其实跟我另一篇博客介绍的东西差不多 Android开发 Jetpack Compose FlowColumn与FlowRow瀑布流布局

效果图

代码

//因为LazyVerticalStaggeredGrid是实验性API,所以需要这个注解
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun APage() {
    val listData = remember {
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
        )
    }
    Column {
        //LazyVerticalStaggeredGrid
        //StaggeredGridCells设置显示几列
        LazyVerticalStaggeredGrid(columns = StaggeredGridCells.Fixed(4)) {
            items(listData.size){
                //这边设置一个item的随机高度,产生随机高度的瀑布效果
                val height = (80..200).random()
                Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(10.dp).background(
                    Color.Gray)) {
                    Image(painter = painterResource(id = listData[it].second), contentDescription = null, modifier = Modifier
                        .width(90.dp)
                        .height(height.dp))
                    Text(text = listData[it].first, fontSize = 18.sp)
                }
            }
        }
    }
}

LazyHorizontalStaggeredGrid 横向瀑布列表

效果图

代码

//因为LazyHorizontalStaggeredGrid是实验性API,所以需要这个注解
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun APage() {
    val listData = remember {
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
        )
    }
    Column {
        //LazyHorizontalStaggeredGrid
        //StaggeredGridCells设置显示几行
        LazyHorizontalStaggeredGrid(rows = StaggeredGridCells.Fixed(4)) {
            items(listData.size){
                //这边设置一个item的随机宽度,产生随机宽度的瀑布效果
                val width = (80..200).random()
                Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(10.dp).background(
                    Color.Gray)) {
                    Image(painter = painterResource(id = listData[it].second), contentDescription = null, modifier = Modifier
                        .width(width.dp)
                        .height(90.dp))
                    Text(text = listData[it].first, fontSize = 18.sp)
                }
            }
        }
    }
}

列表的滚动监听与设置滚动位置

这里使用LazyColumn举例,因为其他形式的列表基本差不多。如果你不太了解下面代码中的rememberCoroutineScope,请参考博客 Android开发 Jetpack_Compose_6 附带效应  这属于附带效应中的知识。 如果你疑问为什么要使用rememberCoroutineScope?这是因为onClick不属于协程域和compose域,而rememberLazyListState需要协程域内才能调用。

效果图

代码

@Composable
fun APage() {
    val listData = remember {
        mutableStateListOf(
            "苹果" to R.mipmap.ic_fruit_apple,
            "香蕉" to R.mipmap.ic_fruit_banana,
            "牛油果" to R.mipmap.ic_fruit_avocado,
            "蓝莓" to R.mipmap.ic_fruit_blueberry,
            "椰子" to R.mipmap.ic_fruit_coconut,
            "葡萄" to R.mipmap.ic_fruit_grape,
            "哈密瓜" to R.mipmap.ic_fruit_hami_melon,
            "猕猴桃" to R.mipmap.ic_fruit_kiwifruit,
            "柠檬" to R.mipmap.ic_fruit_lemon,
            "荔枝" to R.mipmap.ic_fruit_litchi,
            "芒果" to R.mipmap.ic_fruit_mango,
        )
    }
    //协程范围
    val coroutineScope = rememberCoroutineScope()
    //关键代码!滚动状态监听
    val listState = rememberLazyListState()
    Column {
        DescribeText(text = "当前位置 = ${listState.firstVisibleItemIndex}")
        DescribeText(text = "滚动偏移量 = ${listState.firstVisibleItemScrollOffset}")
        DescribeText(text = "是否正在滚动 = ${listState.isScrollInProgress}")
        DescribeText(text = "可以向前滚动(是否可以向下滚) = ${listState.canScrollForward}")
        DescribeText(text = "可以向后滚动(是否可以向上滚) = ${listState.canScrollBackward}")
        Button(modifier = Modifier.fillMaxWidth(), onClick = {
            coroutineScope.launch {
                listState.scrollToItem(0)//关键代码!点击回到最上面
            }
        }) {
            Text(text = "回到最上面")
        }
        LazyColumn(
            state = listState,
            verticalArrangement = Arrangement.Center,
            modifier = Modifier.fillMaxSize(),
        ) {
            items(listData.size) {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.padding(20.dp)
                ) {
                    Image(
                        painter = painterResource(id = listData[it].second),
                        contentDescription = null,
                        modifier = Modifier
                            .width(100.dp)
                            .height(100.dp)
                    )
                    Text(
                        text = listData[it].first,
                        fontSize = 25.sp,
                        modifier = Modifier.padding(start = 80.dp)
                    )
                }
            }
        }
    }
}

@Composable
fun DescribeText(text:String) {
    Text(text = text, color = Color.Black, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth())
}

使用pullRefresh实现下拉加载与上拉加载

 

 

 

 

拖拽

 

end