渲染控制语法
ArkUI 开发框架是一套构建 HarmonyOS / OpenHarmony 应用界面的声明式 UI 开发框架,它支持程序使用 if/else
条件渲染, ForEach
循环渲染以及 LazyForEach
懒加载渲染。本节笔者介绍一下这三种渲染方式的使用。
if/else 条件渲染
使用 if/else
进行条件渲染需要注意以下情况:
if
条件语句可以使用状态变量。
使用 if
可以使子组件的渲染依赖条件语句。
必须在容器组件内使用。
某些容器组件限制子组件的类型或数量。将 if
放置在这些组件内时,这些限制将应用于 if
和 else
语句内创建的组件。例如,Grid
组件的子组件仅支持 GridItem
组件,在 Grid
组件内使用条件渲染时,则 if
条件语句内仅允许使用 GridItem
组件。
简单样例如下所示:
@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
定义如下:
interface ForEach {
(
arr: Array<any>,
itemGenerator: (item: any, index?: number) => void,
keyGenerator?: (item: any, index?: number) => string
): ForEach;
}
arr: 必须是数组,允许空数组,空数组场景下不会创建子组件。
itemGenerator:子组件生成函数,为给定数组项生成一个或多个子组件。
keyGenerator:匿名参数,用于给定数组项生成唯一且稳定的键值。
简单如下:
@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 接口
// 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 定义如下:
export declare interface IDataSource {
totalCount(): number;
getData(index: number): any;
registerDataChangeListener(listener: DataChangeListener): void;
unregisterDataChangeListener(listener: DataChangeListener): void;
}
totalCount
:获取数据总数。getData
:获取索引对应的数据。registerDataChangeListener
:注册改变数据的监听器。unregisterDataChangeListener
:注销改变数据的监听器。
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;
}
onDataReloaded:item 重新加载数据时的回调。
onDataAdded:item 新添加数据时的回调。
onDataMoved:item 数据移动时的回调。
onDataDeleted:item 数据删除时的回调。
onDataChanged:item 数据变化时的回调。
简单样例如下:
// 定义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 开发框架的渲染控制语法,读者熟练掌握后可以随心所欲的控制页面的显示逻辑了