Compose | UI组件(十二) | Lazy Layout - 列表

文章目录

  • 前言
    • LazyListScope作用域 用来干什么?
    • LazyColumn组件含义?
    • LazyColumn的基本使用
      • LazyColumn Padding设置边距
      • LazyColumn 设置边距 (contentPadding)
      • LazyColumn 为每个子项设置边距 (Arrangement.spacedBy())
      • LazyColumn 根据 rememberLazyListState 记录item位置
      • 根据 items函数 新增 一个key参数,增加和删除操作时,提高页面性能问题
    • LazyRow的含义
      • LazyRow的使用
  • 总结


前言

现在应用市场上很多产品都少不了列表展示需求场景,例如通讯录,短信,音乐列表等等。

所以本篇文章讲解的组件 - 列表LazyListLazyRow


在了解 LazyListLazyRow 之前,我们先了解下 LazyListScope作用域

LazyListScope作用域 用来干什么?

LazyColumnLazyRow 内部都是继承 LazyList组件 实现,但 LazyList 不能直接使用

LazyListcontent 是一个 LazyListScope.() -> Unit 类型的作用域
LazyListScope 提供了 item , items(Int) , item(List) , itemsIndexed(List) 扩展函数来展示列表内容

item:展示单项数据
items(Int):展示多项整型数据
items(List) 展示一组集合数据
itemsIndexed(List) 展示一组集合数据,并且带有下标

val list = ('A'..'Z').map { it.toString() }
LazyColumn{
    item { Text(text = "first item") }
    
    items(10){ index ->
        Text(text = "$index")
    }

    item { Text(text = "last item") }

    items(list){  item ->
        Text(text = item)
    }

    itemsIndexed(list){ index, item ->
        Text(text = "$index/$item")
    }
}

LazyColumn组件含义?

LazyColumn 就是一个纵向滚动列表,用来显示一组纵向数据,并且可以滑动列表

@Composable
fun LazyColumn(
    modifier: Modifier = Modifier,                                     //修饰符
    state: LazyListState = rememberLazyListState(),                    //记录列表位置状态
    contentPadding: PaddingValues = PaddingValues(0.dp),               //整体内容周围的一个边距
    reverseLayout: Boolean = false,                                    //是否反转列表
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,   //子组件纵向对齐方式
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,       //子组件横向对齐方式
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), //fling行为处理逻辑
    userScrollEnabled: Boolean = true,                                 //是否允许滑动
    content: LazyListScope.() -> Unit                                  //LazyList作用域
)

LazyColumn的基本使用

LazyColumn 组件 相比传统的 RecyclerView 少写很多代码
RecyclerView 需要在xml中声明一个RecyclerView控件,再在xml中声明一个子控件,再创建一个适配器Adapter,最后在activity中 指定 RecyclerView 的布局类型,再为其填充数据
LazyColumn 就很简单了,看如下代码的实现,就知道了

@Composable
fun LazyColumnList() {
    LazyColumn {
        items(20) { i ->
            Text(
                text = "Item $i",
                modifier = Modifier
                    .fillMaxWidth()
                    .height(60.dp)
            )
        }
    }
}

LazyColumn Padding设置边距

Padding可以设置列表边距,但是会出现切割现象,我们来看下代码

    val list = ('A'..'Z').map { it.toString() }
    LazyColumn {
        itemsIndexed(list) { index, letter ->
            Card(
                modifier = Modifier
                    .width(120.dp)
                    .height(200.dp)
                    .padding(10.dp)
            ) {
                Text(
                    text = "$index $letter",
                    textAlign = TextAlign.Center,
                    fontSize = 20.sp,
                    modifier = Modifier
                        .fillMaxSize()
                        .wrapContentHeight(Alignment.CenterVertically)
                )
            }
        }
    }

现在看下运行代码的效果:
Compose | UI组件(十二) | Lazy Layout - 列表_第1张图片

注:
从上图可以看出来最后一个出现了被切割现象,那如何解决这个问题呢?

那就要用到 LazyColumn 提供的 contentPadding 解决

LazyColumn 设置边距 (contentPadding)

LazyColumn 设置边距用的是contentPadding,能保证上下两边的边距相等同时,还不会在滚动的时候,出现切割现象

val list = ('A'..'Z').map { it.toString() }
LazyColumn(contentPadding = PaddingValues(top = 40.dp, start = 10.dp, bottom = 40.dp, end = 10.dp)) {
     itemsIndexed(list) { index, letter ->
         Card(
             modifier = Modifier
                 .fillMaxWidth()
                 .height(120.dp)
//                    .padding(10.dp)
         ) {
             Text(
                 text = "$index $letter",
                 textAlign = TextAlign.Center,
                 fontSize = 20.sp,
                 modifier = Modifier.fillMaxSize().wrapContentHeight(Alignment.CenterVertically)
             )
         }
     }
 }

现在再看下效果图:
Compose | UI组件(十二) | Lazy Layout - 列表_第2张图片

注:
现在可以看出来,没有切割的现象了,但有个问题,中间没有了间距
Lazy Layout提供了专门给子项之间设置边距的属性,使用Arrangement.spacedBy()即可

LazyColumn 为每个子项设置边距 (Arrangement.spacedBy())

Arrangement.spacedBy() 专门为子项设置边距

val list = ('A'..'Z').map { it.toString() }
LazyColumn(contentPadding = PaddingValues(top = 40.dp, start = 10.dp, bottom = 40.dp, end = 10.dp),
           verticalArrangement = Arrangement.spacedBy(20.dp)) {
		    itemsIndexed(list) { index, letter ->
		        Card(
		            modifier = Modifier
		                .fillMaxWidth()
		                .height(120.dp)
		        ) {
		            Text(
		                text = "$index $letter",
		                textAlign = TextAlign.Center,
		                fontSize = 20.sp,
		                modifier = Modifier.fillMaxSize()
		                                   .wrapContentHeight(Alignment.CenterVertically)
		            )
		        }
    }
}

效果图如下:
Compose | UI组件(十二) | Lazy Layout - 列表_第3张图片

LazyColumn 根据 rememberLazyListState 记录item位置

有时候有这样的需求:让组件随着列表的滚动进行一些额外的响应。如随着滚动隐藏和显示某个组件
这时候 rememberLazyListState 就排上用场了

以下是rememberLazyListState 源码:

@Composable
fun rememberLazyListState(
    initialFirstVisibleItemIndex: Int = 0,        //第一个可见子项元素的下标
    initialFirstVisibleItemScrollOffset: Int = 0  //第一个可见子项元素的偏移距离
): LazyListState {
    return rememberSaveable(saver = LazyListState.Saver) {
        LazyListState(
            initialFirstVisibleItemIndex,
            initialFirstVisibleItemScrollOffset
        )
    }
}

根据列表第一项可见显示组件,不可见隐藏组件

@SuppressLint("FrequentlyChangedStateReadInComposition")
@Composable
fun ListLayout() {
    val state = rememberLazyListState()
    Box {
        val list = ('A'..'Z').map { it.toString() }
        LazyColumn(state = state,
            contentPadding = PaddingValues(top = 40.dp, start = 10.dp, bottom = 40.dp, end = 10.dp),
            verticalArrangement = Arrangement.spacedBy(20.dp)) {
            itemsIndexed(list) { index, letter ->
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(120.dp)
                ) {
                    Text(
                        text = "$index $letter",
                        textAlign = TextAlign.Center,
                        fontSize = 20.sp,
                        modifier = Modifier
                            .fillMaxSize()
                            .wrapContentHeight(Alignment.CenterVertically)
                    )
                }
            }
        }

        if (state.firstVisibleItemIndex  == 0) {
            FloatingActionButton(
                onClick = {},
                shape = CircleShape,
                modifier = Modifier
                    .align(Alignment.CenterEnd)
                    .padding(20.dp)
            ) {
                Icon(Icons.Filled.Star, "Add Button")
            }
        }
    }
}

根据 items函数 新增 一个key参数,增加和删除操作时,提高页面性能问题

因为compose中往列表添加一项数据,就会整体往后移,数据越多,页面性能越差
所以Google给出了一个解决方案:在items函数添加一个唯一标识的key

@Composable
fun SubVerticalScrollable() {
    val list = ('A'..'Z').map { it.toString() }
    LazyColumn(modifier = Modifier.height(300.dp)) {
        items(list, key = { it }) { letter ->
            ...
        }
    }
}

LazyRow的含义

LazyRow 和 LazyColumn用法基本相同,唯一不同的是横向布局的列表组件

@Composable
fun LazyRow(
    modifier: Modifier = Modifier,                                     //修饰符
    state: LazyListState = rememberLazyListState(),                    //记录列表位置状态
    contentPadding: PaddingValues = PaddingValues(0.dp),               //整体内容周围的一个边距
    reverseLayout: Boolean = false,                                    //是否反转列表
    horizontalArrangement: Arrangement.Horizontal =
        if (!reverseLayout) Arrangement.Start else Arrangement.End,    //子组件横向对齐方式
    verticalAlignment: Alignment.Vertical = Alignment.Top,             //子组件纵向对齐方式
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), //fling行为处理逻辑
    userScrollEnabled: Boolean = true,                                 //是否允许滑动
    content: LazyListScope.() -> Unit                                  //LazyList作用域
)

LazyRow的使用

LazyRow(contentPadding = PaddingValues(top = 40.dp, start = 10.dp, bottom = 40.dp, end = 10.dp),
	    verticalArrangement = Arrangement.spacedBy(20.dp)) {
	    itemsIndexed(list) { index, letter ->
	        Card(
	            modifier = Modifier
	                .fillMaxWidth()
	                .height(120.dp)
	        ) {
	            Text(
	                text = "$index $letter",
	                textAlign = TextAlign.Center,
	                fontSize = 20.sp,
	                modifier = Modifier
	                    .fillMaxSize()
	                    .wrapContentHeight(Alignment.CenterVertically)
	            )
	        }
	    }
}	

到这里,基本上Lazy Layout 基本上覆盖到了,还有什么问题,可以到官网查询


总结

  1. LazyListScope作用域提供了 item , items(Int) , item(List) , itemsIndexed(List) 扩展函数来展示列表内容
  2. LazyColumn 就是一个纵向滚动列表
  3. contentPadding 设置列表组件的整个内容的边距
  4. Arrangement.spacedBy() 为列表的每个子项设置边距
  5. LazyColumn 根据 rememberLazyListState 记录第一个可见子项元素位置
  6. items函数 新增 一个key参数,设置唯一性,增加和删除操作时,性能得到优化和提高
  7. LazyRow 是一个横向布局的列表组件,用法和 LazyColumn一致

你可能感兴趣的:(Android开发,#,[Compose],Compose,LazyColumn,LazyRow)