Skip to content

渲染控制语法

ArkUI 开发框架是一套构建 HarmonyOS / OpenHarmony 应用界面的声明式 UI 开发框架,它支持程序使用 if/else 条件渲染, ForEach 循环渲染以及 LazyForEach 懒加载渲染。本节笔者介绍一下这三种渲染方式的使用。

if/else 条件渲染

使用 if/else 进行条件渲染需要注意以下情况:

if 条件语句可以使用状态变量。

使用 if 可以使子组件的渲染依赖条件语句。

必须在容器组件内使用。

某些容器组件限制子组件的类型或数量。将 if 放置在这些组件内时,这些限制将应用于 ifelse 语句内创建的组件。例如,Grid 组件的子组件仅支持 GridItem 组件,在 Grid 组件内使用条件渲染时,则 if 条件语句内仅允许使用 GridItem 组件。

简单样例如下所示:

js

@Entry
@Component
struct ComponentTest {
  @State showImage: boolean = false;

  build() {
    Column({ space: 10 }) {

      if (this.showImage) { // 显示图片
        Image($r("app.media.icon"))
          .width(160)
          .height(60)
          .backgroundColor(Color.Pink)
      } else { // 显示文本
        Text('Loading...')
          .fontSize(23)
          .width(160)
          .height(60)
          .backgroundColor(Color.Pink)
      }

      Button(this.showImage ? 'Image Loaded' : 'Load Image')// 按钮文字
        .size({ width: 160, height: 40 })
        .backgroundColor(this.showImage ? Color.Gray : '#aabbcc')// 按钮背景色
        .onClick(() => {
          this.showImage = !this.showImage; // 设置标记位
        })
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }
}

样例运行结果如下图所示:

图片

ForEach 循环渲染

ArkUI 开发框架提供循环渲染(ForEach 组件)来迭代数组,并为每个数组项创建相应的组件。

ForEach 定义如下:

js
interface ForEach {
  (
    arr: Array<any>,
    itemGenerator: (item: any, index?: number) => void,
    keyGenerator?: (item: any, index?: number) => string
  ): ForEach;
}
  • arr: 必须是数组,允许空数组,空数组场景下不会创建子组件。

  • itemGenerator:子组件生成函数,为给定数组项生成一个或多个子组件。

  • keyGenerator:匿名参数,用于给定数组项生成唯一且稳定的键值。

简单如下:

js

@Entry
@Component
struct ComponentTest {
  private textArray: string[] = ["1", "2", "3", "4", "5"]; // 数据源

  build() {
    Column({ space: 10 }) {
      ForEach(this.textArray, (item: string, index?: number) => { // 循环数组创建每一个Item
        Text(`Text: ${item}`)// 可以生成一个或多个子组件
          .fontSize(20)
          .backgroundColor(Color.Pink)
          .margin({ top: 10 })
      })
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }
}

样例运行结果如下图所示:

图片

LazyForEach 循环渲染

ArkUI 开发框架提供数据懒加载( LazyForEach 组件)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。

LazyForEach 定义如下:

  • 必须要继承 IDataSource 接口
js

// LazyForEach定义
interface LazyForEach {(
	dataSource: IDataSource,
  itemGenerator: (item: any, index?: number) => void,
  keyGenerator?: (item: any, index?: number) => string
  ): LazyForEach;
}

// IDataSource定义
export declare interface IDataSource {
  totalCount(): number;
  getData(index: number): any;
  registerDataChangeListener(listener: DataChangeListener): void;
  unregisterDataChangeListener(listener: DataChangeListener): void;
}

// DataChangeListener定义
export declare interface DataChangeListener {
  onDataReloaded(): void;
  onDataAdded(index: number): void;
  onDataMoved(from: number, to: number): void;
  onDataDeleted(index:number): void;
  onDataChanged(index:number): void;
}
  • itemGenerator: 子组件生成函数,为给定数组项生成一个或多个子组件。

  • keyGenerator: 匿名参数,用于给定数组项生成唯一且稳定的键值。

  • dataSource: 实现 IDataSource 接口的对象,需要开发者实现相关接口。

IDataSource 定义如下:

js

export declare interface IDataSource {
  totalCount(): number;
  getData(index: number): any;
  registerDataChangeListener(listener: DataChangeListener): void;
  unregisterDataChangeListener(listener: DataChangeListener): void;
}
  • totalCount:获取数据总数。

  • getData:获取索引对应的数据。

  • registerDataChangeListener:注册改变数据的监听器。

  • unregisterDataChangeListener:注销改变数据的监听器。

DataChangeListener 定义如下:

js

export declare interface DataChangeListener {
  onDataReloaded(): void;
  onDataAdded(index: number): void;
  onDataMoved(from: number, to: number): void;
  onDataDeleted(index:number): void;
  onDataChanged(index:number): void;
}
  • onDataReloaded:item 重新加载数据时的回调。

  • onDataAdded:item 新添加数据时的回调。

  • onDataMoved:item 数据移动时的回调。

  • onDataDeleted:item 数据删除时的回调。

  • onDataChanged:item 数据变化时的回调。

简单样例如下:

js
// 定义Student
class Student {
  public sid: number;
  public name: string;
  public age: number
  public address: string
  public avatar: string
  constructor(sid: number = -1, name: string, age: number = 16, address: string = '北京', avatar: string = "") {
    this.sid = sid;
    this.name = name;
    this.age = age;
    this.address = address;
    this.avatar = avatar;
  }
}

// 定义DataSource
abstract class BaseDataSource<T> implements IDataSource {

  private mDataSource: T[] = new Array();

  constructor(dataList: T[]) {
    this.mDataSource = dataList;
  }

  totalCount(): number {
    return this.mDataSource == null ? 0 : this.mDataSource.length
  }

  getData(index: number): T|null {
    return index >= 0 && index < this.totalCount() ? this.mDataSource[index] : null;
  }

  registerDataChangeListener(listener: DataChangeListener) {
  }

  unregisterDataChangeListener(listener: DataChangeListener) {
  }

}

//
class StudentDataSource extends BaseDataSource<Student> {
  constructor(students: Student[]) {
    super(students)
  }
}

function mock(): Student[] {
  var students = [];
  for(var i = 0; i < 20; i++) {
    students[i] = new Student(i, "student:" + i, i + 10, "address:" + i, "app.media.test")
  }
  return students;
}

@Entry @Component struct ComponentTest {

  // mock数据
  private student: Student[] = mock();

  // 创建dataSource
  private dataSource: StudentDataSource = new StudentDataSource(this.student);

  build() {
    Column({space: 10}) {
      List() {
        LazyForEach(this.dataSource, (item: Student) => {// LazyForEach使用自定义dataSource
          ListItem() {
            Row() {
              Image($r("app.media.test"))
                .height('100%')
                .width(80)
              Column() {
                Text(this.getName(item)) // 调用getName验证懒加载
                  .fontSize(20)
                Text('address: ' + item.address)
                  .fontSize(17)
              }
              .margin({left: 5})
              .alignItems(HorizontalAlign.Start)
              .layoutWeight(1)
            }
            .width('100%')
            .height('100%')
          }
          .width('100%')
          .height(60)
        })
      }
      .divider({
        strokeWidth: 3,
        color: Color.Gray
      })
      .width('90%')
      .height(160)
      .backgroundColor(Color.Pink)
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }

  getName(item: Student): string {
    console.log("index: " + item.sid); // 打印item下标日志
    return 'index:' + item.sid + ", " + item.name;
  }
}

使用懒加载,可以有效的降低资源占用

小结

本节主要讲解了 ArkUI 开发框架的渲染控制语法,读者熟练掌握后可以随心所欲的控制页面的显示逻辑了