Bootstrap

HarmonyOS瀑布流的实现-------唐朝诡事录人物简介


介绍

  • 当下的大多数产品中瀑布流是一种非常常见的组件,本文将介绍关于waterflow的图片浏览

功能介绍

  • 使用瀑布流实现图片展示
  • 如下图是利用瀑布流做的一个唐朝诡事录人物简介
    瀑布流案例

代码结构

├──entry/src/main/ets                     // 代码区
│  ├──common
│  ├──entryability
│  │  └──EntryAbility.ets                 // 程序入口类
│  ├──pages
│  │  └──Index.ets                     // 主界面
│  ├──view
│  │  ├──FlowItemComponent.ets            // 瀑布流Item组件类
│  │  └──WaterFlowComponent.ets           // 自定义组件类
│  └──viewmodel
│     ├──HomeViewModel.ets                // 瀑布流数据类
│     ├──ProductItem.ets                  // 数据结构类
│     └──WaterFlowDataSource.ets          // 瀑布流数据类

页面布局

@Entry
@Component
struct Index {

  build() {
      Column() {
        WaterFlowComponent();
      }
  }
}

整体结构非常简单就只有一个瀑布流组件。
由于数据量较多,所以我们这里采用懒加载(LazyForEach)方式。
使用LazyForEach进行数据懒加载,要求数据源实现IDataSource接口及成员方法。使用常量waterFlowData完成瀑布流数据项配置,包含图片资源。

数据结构类

首先根据自己的需求定义一个人物信息类和和其接口

export interface IProductItem{

  image_url:Resource;
  name:string;
  introduce:string;
}

export default class ProductItem implements IProductItem{
  image_url: Resource; //人物图片
  name: string;//人物姓名
  introduce: string;//人物简介

  constructor(props:ProductItem) {
    this.image_url = props.image_url;
    this.name = props.name;
    this.introduce = props.introduce;
  }
}

瀑布流数据数组

export class WaterFlowDataSource implements IDataSource{
    private dataArray:ProductItem[] = [];
    private listeners:DataChangeListener[]=[];


//设置瀑布流数据数组
    public setDataArray(productDataArray:ProductItem[]):void{
        this.dataArray = productDataArray;
    }

    //数据的总数
    public totalCount(): number {
        return this.dataArray.length;
    }

    public getData(index: number): ProductItem {
        return this.dataArray[index];
    }

    //注册数据改变的监听器
    registerDataChangeListener(listener: DataChangeListener): void {
        if(this.listeners.indexOf(listener)<0){
            this.listeners.push(listener);
        }
    }

    //注销数据改变的监听器
    unregisterDataChangeListener(listener: DataChangeListener): void {
        let pos =this.listeners.indexOf(listener);
        if(pos>=0){
            this.listeners.splice(pos,1);
        }
    }
}

瀑布流数据资源

资源图片均存放在resource中的media目录中,下面直接代码中直接引用即可

const waterFlowData:IProductItem[]=[
  {
    image_url:$r('app.media.suwuming'),
    name:'苏无名',
    introduce:'狄公弟子'
  },
  {
    image_url:$r('app.media.lulingfeng'),
    name:'卢凌风',
    introduce:'前金吾卫中郎将'
  },
  {
    image_url:$r('app.media.feijishi'),
    name:'费鸡师',
    introduce:'神医'
  },
  {
    image_url:$r('app.media.xijun'),
    name:'裴喜君',
    introduce:'擅长丹青'
  },
  {
    image_url:$r('app.media.yingtao'),
    name:'樱桃',
    introduce:'侠女'
  },
  {
    image_url:$r('app.media.taizi'),
    name:'太子李隆基',
    introduce:'唐玄宗'
  },
  {
    image_url:$r('app.media.gongzhu'),
    name:'公主',
    introduce:'太平公主'
  },
  {
    image_url:$r('app.media.qinxiaobai'),
    name:'秦孝白',
    introduce:'大唐第一画师'
  },
  {
    image_url:$r('app.media.liushiba'),
    name:'刘十八',
    introduce:'甘棠驿'
  },
  {
    image_url:$r('app.media.dugu'),
    name:'独孤遐叔',
    introduce:'爱做梦'
  },
  {
    image_url:$r('app.media.qinghong'),
    name:'轻红',
    introduce:'独孤遐叔之妻'
  },
]

export {waterFlowData};

瀑布流组件中子组件的构建

@Component
export default struct FlowItemComponent {
  item: ProductItem = waterFlowData[0];

  build() {
  //这个子组件采用Column布局 
    Column(){
    //图片的相关设置
      Image(this.item?.image_url)
        .width(400)
        .height(100)
        .objectFit(ImageFit.Contain)
        .margin({
          top:12,
          bottom:12
        })
        //姓名的相关设置
      Text(this.item?.name)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .alignSelf(ItemAlign.Start)
        .fontColor(Color.Black)
        //简介的相关设置
      Text(this.item?.introduce)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .alignSelf(ItemAlign.Start)
        .fontColor(Color.Black)
    }
    .borderRadius(10)
    .backgroundColor(Color.White)
    .padding({
      left:5,
      right:5,
      bottom:5
    })
  }

}

瀑布流效果的实现

瀑布流效果实现步骤如下:

  1. 在生命周期函数aboutToAppear()中初始化瀑布流数据。
  2. WaterFlow容器添加参数footer设置瀑布流滑动至尾部时展示的内容,提示已滑动到底部。
  3. LazyForEach()从数据源中按需迭代数据,在瀑布流容器子组件FlowItem内展示数据项。
  4. 使用瀑布流属性layoutDirection设置主轴方向为FlexDirection.Column列方向,columnsTemplate设置布局列数为两列,columnsGap列间距及rowsGaph行间距
@Component
export default struct WaterFlowComponent{
    private datasource:WaterFlowDataSource = new WaterFlowDataSource();

    aboutToAppear(): void {
    //初始化瀑布流数据
        this.datasource.setDataArray(waterFlowData);

    }

    build() {
        WaterFlow({footer:():void => this.itemFoot()}){
            LazyForEach(this.datasource,(item1:ProductItem)=>{
            //瀑布流容器子组件
                FlowItem(){
                //展示数据项
                    FlowItemComponent({item:item1})
                }
            },(item:ProductItem,index:number)=>JSON.stringify(item)+index.toString())//将对象转换为字符串
        }
        //对子组件重新布局
        .layoutWeight(1)
        //布局的主轴方向为列方向
        .layoutDirection(FlexDirection.Column)
        //列布局设置为两列
.columnsTemplate('1fr 1fr')
		//设置列间距
        .columnsGap(1)
        //设置行间距
        .rowsGap(1)
    }


//瀑布流尾部显示内容
    @Builder
    itemFoot() {
        Column() {
            Text('已经到底了')
                .fontColor(Color.Gray)
                .fontSize(15)
                .width('100%')
                .height(20)
                .textAlign(TextAlign.Center)
        }
    }
}
;