轻松学会如何用List实现左右两边一起滑动

134 阅读5分钟

轻松学会如何用List实现左右两边一起滑动

在手机应用当中我们经常看到这样的界面:

1723376576164.png

这样的界面通常是一起滑动的,比如说左边的List列表滑到了B,那么右边的字母表B也会高亮,点击字母表的字母右边的列表也会跳转到相应的位置。

下面是具体步骤

1.静态布局

我们需要用到List组件、Stack组件和AlphabetIndexer功能组件

List用来实现左边列表、AlphabetIndexer实现右边字母表、Stack把他们放在一起

代码:

hotCitys: string[] =
    ['北京', '上海', '广州', '深圳', '天津', '杭州', '南京', '苏州', '成都', '武汉', '重庆', '西安', '香港', '澳门',
      '台北']
  historyCitys: string[] = ['北京', '上海', '广州', '深圳', '重庆']
  cityContentList: BKCityContent[] = [
    {
      initial: 'A',
      cityNameList: ['阿拉善', '鞍山', '安庆', '安阳', '阿坝', '安顺']
    },
    {
      initial: 'B',
      cityNameList: ['北京', '保定', '包头', '巴彦淖尔', '本溪', '白山']
    },
    {
      initial: 'C',
      cityNameList: ['成都', '重庆', '长春', '长沙', '承德', '沧州']
    },
    {
      initial: 'D',
      cityNameList: ['大连', '东莞', '大同', '丹东', '大庆', '大兴安岭']
    },
    {
      initial: 'E',
      cityNameList: ['鄂尔多斯', '鄂州', '恩施', '额尔古纳市', '二连浩特市', '恩施市']
    },
    {
      initial: 'F',
      cityNameList: ['福州', '佛山', '抚顺', '阜新', '阜阳', '抚州']
    },
    {
      initial: 'G',
      cityNameList: ['广州', '贵阳', '赣州', '桂林', '贵港', '广元']
    },
    {
      initial: 'H',
      cityNameList: ['杭州', '海口', '哈尔滨', '合肥', '呼和浩特', '邯郸']
    },
    {
      initial: 'J',
      cityNameList: ['济南', '晋城', '晋中', '锦州', '吉林', '鸡西']
    },
    {
      initial: 'K',
      cityNameList: ['昆明', '开封', '康定市', '昆山', '康保县', '宽城满族自治县']
    },
    {
      initial: 'L',
      cityNameList: ['兰州', '廊坊', '临汾', '吕梁', '辽阳', '辽源']
    },
    {
      initial: 'M',
      cityNameList: ['牡丹江', '马鞍山', '茂名', '梅州', '绵阳', '眉山']
    },
    {
      initial: 'N',
      cityNameList: ['南京', '宁波', '南昌', '南宁', '南通', '南平']
    },
    {
      initial: 'P',
      cityNameList: ['盘锦', '莆田', '萍乡', '平顶山', '濮阳', '攀枝花']
    },
    {
      initial: 'Q',
      cityNameList: ['青岛', '秦皇岛', '齐齐哈尔', '七台河', '衢州', '泉州']
    },
    {
      initial: 'R',
      cityNameList: ['日照', '日喀则', '饶阳县', '任丘市', '任泽区', '饶河县']
    },
    {
      initial: 'S',
      cityNameList: ['上海', '苏州', '深圳', '沈阳', '石家庄', '朔州']
    },
    {
      initial: 'T',
      cityNameList: ['天津', '太原', '唐山', '通辽', '铁岭', '通化']
    },
    {
      initial: 'W',
      cityNameList: ['无锡', '武汉', '乌海', '乌兰察布', '温州', '芜湖']
    },
    {
      initial: 'X',
      cityNameList: ['厦门', '西安', '西宁', '邢台', '忻州', '兴安盟']
    },
    {
      initial: 'Y',
      cityNameList: ['扬州', '阳泉', '运城', '营口', '延边', '伊春']
    },
    {
      initial: 'Z',
      cityNameList: ['郑州', '珠海', '张家口', '镇江', '舟山', '漳州']
    }
  ]
  alphabets: string[] =
    ['#', '热', "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "W", "X", "Y",
      "Z"]
//自定义的字体组件
        @Builder
  myCity(item: string) {
    Text(item)
      .width("33%")
      .textAlign(TextAlign.Center)
      .padding(15)
  }
//Stack布局,所有内容都在Stack里
Stack({ alignContent: Alignment.End }) {
      //   1城市
      List({ scroller: this.scroller }) {
        ListItemGroup({ header: this.header("历史"), space: 10 }) {
          ListItem() {
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.historyCitys, (item: string) => {
                this.myCity(item)
              })
            }
          }
        }

        //   热门城市
        ListItemGroup({ header: this.header("热门") }) {
          ListItem() {
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.hotCitys, (item: string) => {
                this.myCity(item)
              })
            }
          }
        }

        ForEach(this.cityContentList, (item1: BKCityContent) => {
          ListItemGroup({ header: this.header(item1.initial) }) {
            ForEach(item1.cityNameList, (item2: string) => {
              ListItem() {
                this.myCity(item2)
              }
            })
          }
        })
      }
      .divider({ strokeWidth: 1, startMargin: 20, color: Color.Pink })
      .width("100%")

      //   2字母表
      AlphabetIndexer({ arrayValue: this.alphabets, selected: this.currentSelect })
    //设置外观
        .itemSize(30)
        .selectedFont({ size: 20 })
        .font({ size: 20 })
    }

最后的效果:

1723377590485.png

2.数据渲染、

先创建一个控制器

设置给List

1、scroller:ListScroller=new ListScroller()
2、List(this.scroller)

我们通过onScrollIndex获取当前ListItemGroup的索引

1723377861647.png

.onScrollIndex((start: number) => {
//this.currentSelect是创建字母表时定义的响应变量
        this.currentSelect = start
      })
//这样左右两边的索引就同步了,也就是右边跟随左边滑动高亮

要实现点击跳转需要用到AlphabetIndexer的onSelect事件,以及调用控制器方法

.onSelect((index: number) => {
index 为点击字母索引,这里currSelect更新,字母表对应高亮
          this.currentSelect = index
          //调用控制器方法,左边列表跳转到点击字母对应的索引
          this.scroller.scrollToIndex(this.currentSelect)
        })

完整代码:

@Entry
@Component
struct Index {
  hotCitys: string[] =
    ['北京', '上海', '广州', '深圳', '天津', '杭州', '南京', '苏州', '成都', '武汉', '重庆', '西安', '香港', '澳门',
      '台北']
  historyCitys: string[] = ['北京', '上海', '广州', '深圳', '重庆']
  cityContentList: BKCityContent[] = [
    {
      initial: 'A',
      cityNameList: ['阿拉善', '鞍山', '安庆', '安阳', '阿坝', '安顺']
    },
    {
      initial: 'B',
      cityNameList: ['北京', '保定', '包头', '巴彦淖尔', '本溪', '白山']
    },
    {
      initial: 'C',
      cityNameList: ['成都', '重庆', '长春', '长沙', '承德', '沧州']
    },
    {
      initial: 'D',
      cityNameList: ['大连', '东莞', '大同', '丹东', '大庆', '大兴安岭']
    },
    {
      initial: 'E',
      cityNameList: ['鄂尔多斯', '鄂州', '恩施', '额尔古纳市', '二连浩特市', '恩施市']
    },
    {
      initial: 'F',
      cityNameList: ['福州', '佛山', '抚顺', '阜新', '阜阳', '抚州']
    },
    {
      initial: 'G',
      cityNameList: ['广州', '贵阳', '赣州', '桂林', '贵港', '广元']
    },
    {
      initial: 'H',
      cityNameList: ['杭州', '海口', '哈尔滨', '合肥', '呼和浩特', '邯郸']
    },
    {
      initial: 'J',
      cityNameList: ['济南', '晋城', '晋中', '锦州', '吉林', '鸡西']
    },
    {
      initial: 'K',
      cityNameList: ['昆明', '开封', '康定市', '昆山', '康保县', '宽城满族自治县']
    },
    {
      initial: 'L',
      cityNameList: ['兰州', '廊坊', '临汾', '吕梁', '辽阳', '辽源']
    },
    {
      initial: 'M',
      cityNameList: ['牡丹江', '马鞍山', '茂名', '梅州', '绵阳', '眉山']
    },
    {
      initial: 'N',
      cityNameList: ['南京', '宁波', '南昌', '南宁', '南通', '南平']
    },
    {
      initial: 'P',
      cityNameList: ['盘锦', '莆田', '萍乡', '平顶山', '濮阳', '攀枝花']
    },
    {
      initial: 'Q',
      cityNameList: ['青岛', '秦皇岛', '齐齐哈尔', '七台河', '衢州', '泉州']
    },
    {
      initial: 'R',
      cityNameList: ['日照', '日喀则', '饶阳县', '任丘市', '任泽区', '饶河县']
    },
    {
      initial: 'S',
      cityNameList: ['上海', '苏州', '深圳', '沈阳', '石家庄', '朔州']
    },
    {
      initial: 'T',
      cityNameList: ['天津', '太原', '唐山', '通辽', '铁岭', '通化']
    },
    {
      initial: 'W',
      cityNameList: ['无锡', '武汉', '乌海', '乌兰察布', '温州', '芜湖']
    },
    {
      initial: 'X',
      cityNameList: ['厦门', '西安', '西宁', '邢台', '忻州', '兴安盟']
    },
    {
      initial: 'Y',
      cityNameList: ['扬州', '阳泉', '运城', '营口', '延边', '伊春']
    },
    {
      initial: 'Z',
      cityNameList: ['郑州', '珠海', '张家口', '镇江', '舟山', '漳州']
    }
  ]
  alphabets: string[] =
    ['#', '热', "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "W", "X", "Y",
      "Z"]
  @State currentSelect: number = 0
  @Builder
  header(title: string) {
    Text(title)
      .fontSize(20)
  }

  // 创建控制器
  scroller: ListScroller = new ListScroller()

//自定义组件
@Builder
  myCity(item: string) {
    Text(item)
      .width("33%")
      .textAlign(TextAlign.Center)
      .padding(15)
  }
build() {
    Column() {
     Stack({ alignContent: Alignment.End }) {
      //   1城市
      List({ scroller: this.scroller }) {
        ListItemGroup({ header: this.header("历史"), space: 10 }) {
          ListItem() {
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.historyCitys, (item: string) => {
                this.myCity(item)
              })
            }
          }
        }

        //   热门城市
        ListItemGroup({ header: this.header("热门") }) {
          ListItem() {
            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.hotCitys, (item: string) => {
                this.myCity(item)
              })
            }
          }
        }

        ForEach(this.cityContentList, (item1: BKCityContent) => {
          ListItemGroup({ header: this.header(item1.initial) }) {
            ForEach(item1.cityNameList, (item2: string) => {
              ListItem() {
                this.myCity(item2)
              }
            })
          }
        })
      }
      .divider({ strokeWidth: 1, startMargin: 20, color: Color.Pink })
      .width("100%")
      // 同步索引,高亮
      .onScrollIndex((start: number) => {
        this.currentSelect = start
      })

      //   2字母表
      AlphabetIndexer({ arrayValue: this.alphabets, selected: this.currentSelect })
        .itemSize(30)
        .selectedFont({ size: 20 })
        .font({ size: 20 })// 点击字母表发生的事件
        .onSelect((index: number) => {
          this.currentSelect = index
          this.scroller.scrollToIndex(this.currentSelect)
        })// 显示弹窗
        .usingPopup(true)
    }
    .backgroundColor(Color.White)
    }
  }
  //定义接口
interface BKCityContent {
  initial: string
  cityNameList: string[]
}