【HarmonyOS5.0实战开发】List组件的使用与AlphabetIndexer联动实践

328 篇文章 0 订阅
315 篇文章 0 订阅

在鸿蒙应用开发中,List组件是一个非常重要的元素,它用于展示一系列数据项,非常适合构建列表界面,例如商品列表、联系人列表、消息列表等,可以轻松高效地显示结构化、可滚动的信息。

1. List组件

1.1. List组件基本用法

List(value?:{space?: number | string, initialIndex?: number, scroller?: Scroller})

参数说明:

  • space:设置子组件在主轴方向的间隔
  • initialIndex:设置List组件初次加载的索引值
  • scroller:绑定可滚动组件控制器**Scroller **/ ListScroller

1.2. 常用属性和事件

image.png

除支持通用事件和滚动组件通用事件外,常用的事件有:

onScrollIndex(event: (start: number, end: number, center: number) => void)

参数说明:

  • start:List组件显示区域内的第一个子组件的索引值
  • end:List显示区域内的最后一个子组件的索引值
  • center:List显示区域内的中间位置的子组件的索引值

1.3. ListScroller控制器

**作用:**List组件的滚动控制器,通过它可以控制List组件的滚动

listScroller: ListScroller = new ListScroller()

常用方法有:

  1. 滚动到指定Index索引,支持设置滑动额外偏移量。
scrollToIndex(value: number, smooth?: boolean, align?: ScrollAlign, options?: ScrollToIndexOptions)

参数说明:

  • value:滚动到index索引对应的ListItemGroup元素
  • smooth?:可选参数,是否开启动画
  • align?:可选参数,滚动到的元素与当前容器的对齐方式
  • options?:设置滑动到指定Index的配置项,如额外偏移量。
  1. 滚动到容器边缘,可滚动到顶部/底部
scrollEdge(value: Edge, options?: ScrollEdgeOptions)

参数说明:

  • value:滚动到的边缘位置,类型:**Edge,可选:**Top/Start (顶部/左端) | Bottom/End(底部/右端)
  • options?:设置滚动到边缘位置的模式 (ScrollEdgeOptions{velocity: number }设置滚动的速度)
  1. 滚动到指定的ListItemGroup中指定的ListItem
scrollToItemInGroup(index: number, indexInGroup: number, smooth?: boolean, align?: ScrollAlign): void

参数说明:

  • index:要滚动到的目标元素所在当前容器中的索引值
  • smooth?:可选参数,是否开启动画
  • align?:可选参数,滚动到的元素与当前容器的对齐方式

说明:ListScroller继承自Scroller,具有Scroller的全部方法。

详情请参考鸿蒙开发文档 - Scroller说明和鸿蒙开发文档 - ListScroller说明

2. 子组件ListItem/ListItemGroup

List组件内部仅支持ListItemListItemGroup子组件,ListItemGroup组件内部仅支持ListItem组件。

2.1. ListItemGroup的基本用法

ListItemGroup(options?: ListItemGroupOptions)

ListItemGroupOptions参数说明

image.png

2.2. ListItemGroup的常用属性

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3. ListItem的基本用法

ListItem(value?: ListItemOptions)	// { style:ListItemStyle}

参数说明:style设置List组件卡片样式。

3. 配合AlphabetIndexer组件

AlphabetIndexer组件可以与List组件联动,用于按逻辑结构快速定位容器显示区域。例如,在城市选择列表中,可以通过AlphabetIndexer实现首字母快速索引和定位。

3.1. AlphabetIndexer的基本使用

作用:可以与容器组件联动用于按逻辑结构快速定位容器显示区域的组件,常配合List组件使用。

AlphabetIndexer(value: {arrayValue: Array<string>, selected: number})

参数说明:

  • arrayValue:字母索引字符串数组,不可设置为空
  • selected:选中项索引值,支持$$双向绑定

3.2. 常用属性和事件

image.png

除支持通用事件外,还支持以下事件:

onSelected(callback: (index: number) => void)

3.3. 配合List组件使用

AlphabetIndexer组件通过监听List组件的onScrollIndex事件来更新其选中状态,同时用户点击索引时,可以通过scrollToIndex方法触发List组件滑动并定位到指定首字母的项 。以下是使用List和ListItem组件,配合AlphabetIndexer的一个示例:

@Entry
@Component
struct ListWithAlphabetIndexer {
  listScroller: ListScroller = new ListScroller()
  /* AlphabetIndexer选中的索引 */
  @State selectedIndex: number = 0
  build() {
    Column() {
      List({scroller: this.listScroller}) {
        ForEach(dataArray, (item, index) => {
          ListItem() {Text(item)}
        })
      }
      .onScrollIndex((firstIndex,lastIndex,centerIndex) => {
        // 更新AlphabetIndexer的选中状态
        this.selectedIndex = firstIndex
      })
      AlphabetIndexer({
        arrayValue: ['A', 'B', 'C', ...], // 索引字符数组
        selected: $$this.selectedIndex // 当前选中的索引,支持双向绑定
      })
        .onSelect((index) => {
          // 根据选中的索引更新List的滚动位置
          this.listScroller.scrollToIndex(index);
        })
    }
  }
}

3.4. 通讯录示例和完整代码:

效果图:

0030086000683885950.20240821142345.11461399527312364575568215694034.gif

具体代码:

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

@Entry
@Component
struct Index {
  /* 数据源 */
  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: ['珍珠', '紫薇', '紫霞', '紫竹', '紫云', '紫燕', '紫鸢', '紫藤', '紫荆', '紫罗兰'] },
  ]

  /* ListItemGroup的头部自定义构建函数 */
  @Builder
  getHeader(initial: string) {
    Text(initial)
      .fontSize(18)
      .fontWeight(FontWeight.Bolder)
      .margin({ left: 10 })
  }

  /* AlphabetIndexer选中作用 */
  @State index: number = 0
  /* list的滚动条控制器 */
  scroller: ListScroller = new ListScroller()

  /* 生成随机颜色 */
  getRandomColor(opacity: number = 1) {
    let red = Math.floor(Math.random() * 255)
    let green = Math.floor(Math.random() * 255)
    let blue = Math.floor(Math.random() * 255)
    return `rgba(${red},${green},${blue},${opacity})`
  }

  build() {
    Column({ space: 15 }) {
      Stack({ alignContent: Alignment.End }) {
        Text('通讯录')
          .fontSize(20)
          .width('100%')
          .textAlign(TextAlign.Center)
          .padding(10)
          .backgroundColor('#fff')
        Image($r('app.media.ic_public_add'))
          .fillColor('#ff777777')
          .width(24)
          .margin({ right: 20 })
      }

      Stack({ alignContent: Alignment.End }) {
        Column() {
          Row({ space: 10 }) {
            Image($r('app.media.ic_public_search'))
              .fillColor('#ff777777')
              .width(18)
            Text('搜索')
          }
          .justifyContent(FlexAlign.Center)
          .borderRadius(21)
          .width('90%')
          .height(42)
          .backgroundColor('#fff')

          List({ space: 10, initialIndex: this.index, scroller: this.scroller }) {
            ForEach(this.contacts, (item: ContactContent) => {
              ListItemGroup({
                header: this.getHeader(item.initial),
              }) {
                ForEach(item.nameList, (name: string) => {
                  ListItem() {
                    Row({ space: 10 }) {
                      Image($r('app.media.user_01'))
                        .width(32)
                        .fillColor('#fff')
                        .backgroundColor(this.getRandomColor())
                        .padding(5)
                        .borderRadius(16)
                      Text(name)
                    }
                    .borderRadius(4)
                    .width('100%')
                    .padding(10)
                    .backgroundColor('#fff')
                  }
                })
              }
              .divider({
                strokeWidth: 1,
                color: 'rgba(0,0,0,0.2)',
                startMargin: 50,
                endMargin: 10
              })
            })
          }
          .height('100%')
          .width('100%')
          .padding(10)
          .scrollBar(BarState.Off)
          .sticky(StickyStyle.Header)
          .onScrollIndex(index => {
            this.index = index
          })
        }

        AlphabetIndexer({
          selected: $$this.index,
          arrayValue: this.contacts.map(item => item.initial)
        })
          .usingPopup(true)// 开启弹框
          .popupColor(Color.Orange)// 弹框中字体颜色
          .popupPosition({ x: 20, y: 0 })// 弹框的位置
          .itemSize(20)// 每个索引组件的大小
          .onSelect(index => {
            this.index = index
            this.scroller.scrollToIndex(index, true)
          })
      }
    }
    .backgroundColor('#f2f4f5')
    .width('100%')
    .height('100%')
  }
}

在这里插入图片描述

  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值