List组件的介绍

455 阅读6分钟

List组件不仅可以进行简单的展示列表,还能实现列表的滚动,但是在日常的开发中,外面还可以用它来实现更加复杂的效果,比如下面的分组展示。

1.基本介绍

动画.gif 实现它的主要组件有:

  1. List作为顶级容器
  2. ListItemGroup 作为分组容器
  3. ListItem作为 List 或者ListItemGroup的子组件

image.png 其中的ListItemGroup组件参数,以对象形式传入。 基本语法结构:

@Entry
@Component
struct ListItemGroup_01 {
  @Builder
  headerBuilder() {
    Text('我是头部')
  }

  @Builder
  footerBuilder() {
    Text('我是底部')
  }

  build() {
    List() {
      ListItemGroup({
        header: this.headerBuilder(),
        footer: this.footerBuilder(),
        space: 20
      }) {
        ListItem() {
          Text('我是内容')
            .backgroundColor(Color.Orange)
        }

        ListItem() {
          Text('我是内容')
            .backgroundColor(Color.Orange)
        }
      }
      .divider({ strokeWidth: 1, color: Color.Orange,startMargin:40 })
    }
  }
}

写在它的小括号里面的属性:

image.png 其中的header和footer都是以Builder构建的对象形式进行传入

image.png 它也有更List一样的分割线属性,是设置在组别与组别之间的

2.案例——通讯录

image.png

2.1 步骤拆解:

2.1.1 定义对象数组

image.png 注意:这里在进行接口定义的时候,要注意在对象数组里面还有一个数组。

2.1.2 构建ListItemGroup里面header参数

image.png 定义好后方便在之后调用

2.1.3 构建ListItemGroup里面的ListItem

image.png

2.1.4 随机颜色的函数

image.png

2.1.5 黏性标题

image.png 注意:这是在List上面进行.出来的

2.1.5 利用双重ForEach进行遍历

image.png 其中的第二个ForEach里面的item.nameList是对象数组里面的每个对象的第二个对象

主要的代码就是这几部分,那么这样就能实现我们彩色的通讯录了

3.1 控制滚动

当我们的列表很长的时候,那么就需要快速滚动到列表的底部或者顶部,那么这个时候就需要使用代码来实现。

关键步骤:

  1. 创建控制器(ListScroller)对象
  2. 设置给 List 组件
  3. 调用控制器对象的方法,实现滚动
// 1. 创建控制器(ListScroller)对象
listScroller: ListScroller = new ListScroller()
// 2. 设置给 List 组件
List({ space: 20, scroller: this.listScroller }) {
  // ...
}


Button() {
  // ...
}
.onClick(() => {
  // 3. 调用控制器对象的方法,实现滚动
    this.ls.scrollToIndex(0, true, ScrollAlign.START)
})

它的参数介绍:

image.png 注意:上面的属性是写在this.ls.scrollToIndex(0, true, ScrollAlign.START)括号里面的。

4.1 事件

    List(){
      // ...
    }
    .onScrollIndex((index: number) => {
      console.log('index:', index)
    })

说明:在每次进行滑动的时候,onScrollIndex会自动的获取当前的ListItemGroup作为一个整体占一个索引值。

5.1 AlphabetIndexer组件

通过 AlphabetIndexer 组件可以与容器组件结合,实现导航联动,以及快速定位的效果 基本写法:

@Entry
@Component
struct ContactsList {
  @State selectedIndex:number = 0
  alphabets: string[] = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
    'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']

  build() {
    Stack({ alignContent: Alignment.End }) {
      // 字母表索引组件
      AlphabetIndexer({ arrayValue: this.alphabets, selected: $$this.selectedIndex })
  
    }
    .width('100%')
    .height('100%')
  }
}

说明:其中的this.alphabets参数为你定义的索引列表;this.selectedIndex参数为初始选中的索引值,若超出索引值范围,则取默认值0,该参数支持双向绑定$$

5.1.1 AlphabetIndexer的一些文字外观设置

image.png 图中各参数的说明已给出。

案例——用户列表联动

image.png 核心步骤: 1.实例化控制器

image.png 2.绑定给List

image.png 3.利用List上面的属性.onScrollIndex来获取当前List上面的索引值,并且将这个索引值赋给这个状态变量

image.png 4.利用Stack层叠布局,将AlphabetIndexer索引组件堆叠在右顶部

image.png 5.将arrayValue参数设置为this.alphabets数组,以及将selected参数设置为状态变量this.selectedIndex

image.png 6.然后在用AlphabetIndexer索引组件里面的onSelect属性 来获取当前索引组件所在的索引值,然后利用onSelect将索引值传给控制器方法的this.ls.scrollToIndex(index)

image.png 完成这些了就完成了我们的联合绑定。

以下的完整代码:

interface ContactContent {
  initial: string
  nameList: string[]
}

@Entry
@Component
struct ContactsList {
  contacts: ContactContent[] = [
    {
      initial: 'A',
      nameList: ['阿斗', '阿猫', '阿狗', '阿虎', '阿龙', '阿鹰', '阿狼', '阿豹', '阿狮', '阿象', '阿鲸']
    },
    { initial: 'B', nameList: ['白兔', '白鸽', '白鹤', '白鹭', '白狐', '白狼', '白虎', '白鹿', '白蛇', '白马'] },
    { initial: 'C', nameList: ['春花', '春风', '春雨', '春草', '春柳', '春燕', '春莺', '春蝶', '春蓝', '春绿'] },
    { initial: 'D', nameList: ['冬雪', '冬梅', '冬松', '冬竹', '冬云', '冬霜', '冬月', '冬夜', '冬青', '冬红'] },
    { initial: 'E', nameList: ['饿狼', '饿虎', '饿鹰', '饿豹', '饿熊', '饿蛇', '饿鱼', '饿虾', '饿蟹', '饿蚌'] },
    { initial: 'F', nameList: ['飞鸟', '飞鱼', '飞虫', '飞蜂', '飞蝶', '飞蛾', '飞蝉', '飞蝗', '飞鼠', '飞猫'] },
    { initial: 'G', nameList: ['孤狼', '孤鹰', '孤虎', '孤豹', '孤蛇', '孤鲨', '孤鲸', '孤鹿', '孤雁', '孤鸿'] },
    { initial: 'H', nameList: ['海鸥', '海龟', '海豚', '海星', '海马', '海葵', '海参', '海胆', '海螺', '海贝'] },
    { initial: 'I', nameList: ['火焰', '火球', '火箭', '火山', '火车', '火柴', '火把', '火鸟'] },
    { initial: 'J', nameList: ['金鱼', '金狮', '金刚', '金鹿', '金蛇', '金鹰', '金豹', '金虎', '金狐', '金猫'] },
    { initial: 'K', nameList: ['孔雀', '恐龙', '开心', '开怀', '开朗', '开拓', '开口', '开花', '开眼', '开天'] },
    { initial: 'L', nameList: ['老虎', '老鹰', '老鼠', '老狼', '老狗', '老猫', '老熊', '老鹿', '老龟', '老蛇'] },
    { initial: 'M', nameList: ['玫瑰', '牡丹', '梅花', '茉莉', '木兰', '棉花', '蜜蜂', '蚂蚁', '马蜂', '蟒蛇'] },
    { initial: 'N', nameList: ['南山', '南极', '南海', '南京', '南阳', '南风', '南瓜', '南竹', '南花', '南鸟'] },
    {
      initial: 'O',
      nameList: ['熊猫', '欧鹭', '欧洲', '欧阳', '欧文', '欧若拉', '欧米茄', '欧罗巴', '欧菲莉亚', '欧瑞斯']
    },
    { initial: 'P', nameList: ['苹果', '葡萄', '琵琶', '枇杷', '菩提', '瓢虫', '瓢泼', '飘零', '飘渺', '飘飘然'] },
    { initial: 'Q', nameList: ['七喜', '强风', '奇迹', '乾坤', '奇才', '晴天', '青竹', '秋水', '轻舞', '清泉'] },
    { initial: 'R', nameList: ['瑞雪', '瑞兽', '瑞光', '瑞云', '瑞彩', '瑞气', '瑞香', '瑞草', '瑞莲', '瑞竹'] },
    { initial: 'S', nameList: ['三羊', '三狗', '三猫', '三鱼', '三角', '三鹿', '三鹰', '三蛇', '三狐', '三豹'] },
    { initial: 'T', nameList: ['太阳', '天空', '田园', '太极', '太湖', '天鹅', '太空', '天使', '坦克', '甜橙'] },
    { initial: 'U', nameList: ['乌鸦', '乌鹊', '乌鱼', '乌龟', '乌云', '乌梅', '乌木', '乌金', '乌黑', '乌青'] },
    { initial: 'V', nameList: ['五虎', '五狼', '五鹰', '五豹', '五熊', '五蛇', '五鲨', '五鲸', '五鹿', '五马'] },
    { initial: 'W', nameList: ['悟空', '微笑', '温暖', '无畏', '温柔', '舞蹈', '问心', '悟道', '未来', '文学'] },
    { initial: 'X', nameList: ['西风', '西洋', '西子', '西施', '西岳', '西湖', '西柚', '西竹', '西花', '西鸟'] },
    { initial: 'Y', nameList: ['夜猫', '夜鹰', '夜莺', '夜空', '夜色', '夜月', '夜影', '夜翼', '夜狐', '夜狼'] },
    { initial: 'Z', nameList: ['珍珠', '紫薇', '紫霞', '紫竹', '紫云', '紫燕', '紫鸢', '紫藤', '紫荆', '紫罗兰'] },
  ]
  alphabets: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
    'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
  @State selectedIndex: number = 0
  ls = new ListScroller()

  /*
   * 需求:
   * 1. 当List滚动的时候,索引组件跟着联动
   *    - 技术拆解: selectedIndex的值改变->索引组件跟着改变
   *    - 使用List上的onScrollIndex() 事件来获取到当前滚动的索引好
   *      List(){}.onScrollIndex((index)=>{
            this.selectedIndex = index
          })
   * 2. 当用户点击索引组件上的字母的时候,List跟着联动
   *  - 技术拆解:List能够根据索引自定定位到某个位置:ListScroller控制对象 scrollToIndex(索引号)
   *  - 索引组件上 onSelect((index)=>{ ListScroller控制对象.scrollToIndex(index)  }) ->
   *
   *
   * */

  // 在结构体中定义一个函数,在试图中使用 this.来调用
  randomColor() {
    let red = Math.floor(Math.random() * 256)
    let green = Math.floor(Math.random() * 256)
    let blue = Math.floor(Math.random() * 256)

    let rStr = `rgba(${red},${green},${blue},0.5)`
    console.log(rStr)

    return rStr
  }

  build() {
    Column() {
      Stack({ alignContent: Alignment.End }) {
        Text('通讯录')
          .width('100%')
          .textAlign(TextAlign.Center)
          .fontSize(20)
        Image($r('app.media.ic_public_add'))
          .width(20)
      }
      .width('100%')
      .padding(15)
      .backgroundColor('#fff1f3f5')

      Row() {
        Image($r('app.media.ic_public_search'))
          .width(20)
          .fillColor(Color.Gray)
        Text('搜索')
          .fontColor(Color.Gray)
      }
      .backgroundColor(Color.White)
      .width('100%')
      .height(40)
      .borderRadius(5)
      .justifyContent(FlexAlign.Center)

      // Stack布局->alignContent:Alignment.End索引组件定位到右边
      Stack({ alignContent: Alignment.End }) {
        // 1. 通讯录List组件
        List({ scroller: this.ls }) {
          ForEach(this.contacts, (item: ContactContent) => {
            ListItemGroup({ header: this.itemHead(item.initial), space: 10 }) {
              // 循环渲染分组A的ListItem
              ForEach(item.nameList, (nickName: string) => {
                this.contactBuilder(nickName, this.randomColor())
              })
            }
            .divider({
              startMargin: 60,
              strokeWidth: 1,
              color: '#ccc'
            })
          })
        }
        .sticky(StickyStyle.Header)
        .onScrollIndex((index) => {
          this.selectedIndex = index
        })
        .scrollBar(BarState.Off)

        // 2. 索引组件布局
        AlphabetIndexer({
          arrayValue: this.alphabets,
          selected: this.selectedIndex
        })
          .itemSize(20)
          .usingPopup(true)
          .popupColor(Color.Orange)
          .popupPosition({ x: 20, y: 0 })
          .onSelect((index) => {
            this.ls.scrollToIndex(index)
          })
      }
    }

  }

  @Builder
  itemHead(text: string) {
    // 列表分组的头部组件,对应联系人分组A、B等位置的组件
    Text(text)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }

  @Builder
  contactBuilder(name: string, color: ResourceColor) {
    ListItem() {
      Row({ space: 10 }) {
        Image($r('app.media.ic_public_lianxiren'))
          .width(40)
          .fillColor(color)
        Text(name)
      }
    }
  }
}