基础知识方面:
由list容器组件和listitem容器组件构成,list是一个大容器,listitem是大容器里的小容器
使用说明
![](https://i-blog.csdnimg.cn/blog_migrate/b6015b25d6e3180e3a1412d68a0edf34.png)
示例
![](https://i-blog.csdnimg.cn/blog_migrate/04fd7582979e16424cf63f1f284aa95f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0235fd89de3d860e48d5bb28a010b7e8.png)
渲染控制:
ArkTS也提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。
条件渲染:
使用if/else进行条件渲染。
![](https://i-blog.csdnimg.cn/blog_migrate/87926b17fbfd07c1306ae921b90ec7eb.png)
Column() {
if (this.count < 0) {
Text('count is negative').fontSize(14)
} else if (this.count % 2 === 0) {
Text('count is even').fontSize(14)
} else {
Text('count is odd').fontSize(14)
}
}
循环渲染:
通过循环渲染(ForEach)从数组中获取数据,并为每个数据项创建相应的组件,可减少代码复杂度。
ForEach(
arr: any[],
itemGenerator: (item: any, index?: number) => void,
keyGenerator?: (item: any, index?: number) => string
)
参数:
参数名 | 参数类型 | 必填 | 参数描述 |
arr | any[] | 是 | 必须是数组,允许设置为空数组,空数组场景下将不会创建子组件。同时允许设置返回值为数组类型的函数,例如arr.slice(1, 3),设置的函数不得改变包括数组本身在内的任何状态变量,如Array.splice、Array.sort或Array.reverse这些改变原数组的函数。 |
itemGenerator | (item: any, index?: number) => void | 是 | 生成子组件的lambda函数,为数组中的每一个数据项创建一个或多个子组件,单个子组件或子组件列表必须包括在大括号“{...}”中。 |
keyGenerator | (item: any, index?: number) => string | 否 | 匿名函数,用于给数组中的每一个数据项生成唯一且固定的键值。当数据项在数组中的位置更改时,其键值不得更改,当数组中的数据项被新项替换时,被替换项的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则ForEach中的所有节点都将重建。 |
![](https://i-blog.csdnimg.cn/blog_migrate/20fcb65fd27a1977bab0ce0810ea70dc.png)
示例:
// xxx.ets
@Entry
@Component
struct MyComponent {
@State arr: number[] = [10, 20, 30]
build() {
Column({ space: 5 }) {
Button('Reverse Array')
.onClick(() => {
this.arr.reverse()
})
ForEach(this.arr, (item: number) => {
Text(`item value: ${item}`).fontSize(18)
Divider().strokeWidth(2)
}, (item: number) => item.toString())
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/a24ea96488b5b0068c28db765fdea5ec.gif)
数据懒加载
通过数据懒加载(LazyForEach)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
LazyForEach(
dataSource: IDataSource,
itemGenerator: (item: any) => void,
keyGenerator?: (item: any) => string
): void
interface IDataSource {
totalCount(): number;
getData(index: number): any;
registerDataChangeListener(listener: DataChangeListener): void;
unregisterDataChangeListener(listener: DataChangeListener): void;
}
interface DataChangeListener {
onDataReloaded(): void;
onDataAdd(index: number): void;
onDataMove(from: number, to: number): void;
onDataDelete(index: number): void;
onDataChange(index: number): void;
}
参数名 | 参数类型 | 必填 | 参数描述 |
dataSource | IDataSource | 是 | 实现IDataSource接口的对象,需要开发者实现相关接口。 |
itemGenerator | (item: any) => void | 是 | 生成子组件的lambda函数,为数组中的每一个数据项创建一个或多个子组件,单个子组件或子组件列表必须包括在大括号“{...}”中。 |
keyGenerator | (item: any) => string | 否 | 匿名函数,用于给数组中的每一个数据项生成唯一且固定的键值。当数据项在数组中的位置更改时,其键值不得更改,当数组中的数据项被新项替换时,被替换项的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则LazyForEach中的所有节点都将重建。 |
IDataSource类型说明
![](https://i-blog.csdnimg.cn/blog_migrate/6f19d4d918a061f675ad819a6792a52c.png)
DataChangeListener类型说明
名称 | 描述 |
onDataReloaded(): void | 重新加载所有数据。 |
onDataAdded(index: number): void (deprecated) | 通知组件index的位置有数据添加。 |
onDataMoved(from: number, to: number): void (deprecated) | 通知组件数据从from的位置移到to的位置。 |
onDataDeleted(index: number): void (deprecated) | 通知组件index的位置有数据删除。 |
onDataChanged(index: number): void (deprecated) | 通知组件index的位置有数据变化。 |
onDataAdd(index: number): void 8+ | 通知组件index的位置有数据添加。 |
onDataMove(from: number, to: number): void 8+ | 通知组件数据从from的位置移到to的位置。 |
onDataDelete(index: number): void 8+ | 通知组件index的位置有数据删除。 |
onDataChange(index: number): void 8+ | 通知组件index的位置有数据变化。 |
示例:
// xxx.ets
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = []
public totalCount(): number {
return 0
}
public getData(index: number): any {
return undefined
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener')
this.listeners.push(listener)
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener')
this.listeners.splice(pos, 1)
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded()
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index)
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index)
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index)
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to)
})
}
}
class MyDataSource extends BasicDataSource {
// 初始化数据列表
private dataArray: string[] = ['/path/image0.png', '/path/image1.png', '/path/image2.png', '/path/image3.png']
public totalCount(): number {
return this.dataArray.length
}
public getData(index: number): any {
return this.dataArray[index]
}
public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data)
this.notifyDataAdd(index)
}
public pushData(data: string): void {
this.dataArray.push(data)
this.notifyDataAdd(this.dataArray.length - 1)
}
}
@Entry
@Component
struct MyComponent {
private data: MyDataSource = new MyDataSource()
build() {
List({ space: 3 }) {
LazyForEach(this.data, (item: string) => {
ListItem() {
Row() {
Image(item).width(50).height(50)
Text(item).fontSize(20).margin({ left: 10 })
}.margin({ left: 10, right: 10 })
}
.onClick(() => {
// 每点击一次列表项,数据增加一项
this.data.pushData('/path/image' + this.data.totalCount() + '.png')
})
}, item => item)
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/84336d976f1709e8258a7d7ca4b864f6.png)
本次作业:
列表示例:
@Entry
@Component
struct zuoye3 {
build() {
Column(){
List( ) {
ListItem(){
Text("示例1")
.fontSize(30).width("100%").height("10%").backgroundColor("#DCDCDC")
}
ListItem(){
Text("示例2")
.fontSize(30).width("100%").height("10%").backgroundColor("#BABABA")
}
ListItem(){
Text("示例3")
.fontSize(30) .width("100%").height("10%").backgroundColor("#BDDB")
}
ListItem(){
Text("示例4")
.fontSize(30).width("100%").height("10%").backgroundColor("#1264")
}
}
}
.width("100%").height("100%").justifyContent(FlexAlign.Center)
}
}
if-else-else if示例:
//import {child} from"../applicationability/child"
@Entry
@Component
struct zuoye5{
@State fathernum : number= -1
build(){
Column(){
Column(){
if(this.fathernum%2===0){
Text('count is negative')
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
else if(this.fathernum%3===0){
Text('even')
.fontSize(50)
.fontWeight(FontWeight.Bold)
} else{
Text('odd')
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
}
}
.width("100%").height("100%").justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
}
}
讲解:if-else组件必须在容器组件内使用。特别需要注意的一点是对于fathernum的赋值情况:其中的
number= -1不可少,因为加了number才能够确定fathernum才有类型。我做的时候犯的错误有,没加number,以及写成了:@State fathernum : number= “-1”,这里是不需要加引号的。
循环渲染示例:
@Entry
@Component
struct zuoye4 {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 一个列表
build() {
Column() {
Column() {
List({ space: 20 }) {
//for循环渲染出10个Listitem小列表
ForEach(this.arr, (item) => {
ListItem() {
//使列表里面的元素转化为字符串出现到文本里
Text(item.toString())
// 设置长度
.width('100%')
// 设置宽度
.height(90)
// 文字大小
.fontSize(36)
// 文字居中
.textAlign(TextAlign.Center)
// 背景颜色
.backgroundColor("#007DEF")
// 使ListItem出现圆角
.borderRadius(30)
}
})
}
// 排列方向
.listDirection(Axis.Vertical)
}
.width("90%")
.height('90%')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.SpaceAround)
}
}
这里需要注意的是:要设置排列的方向 .listDirection(Axis.Vertical)不可少
父子组件:
父组件:
import{child} from"../applicationability/child"
@Entry
@Component
struct zuoye6{
//设fathernum为number类型值为0
@State fathernum:number = 0
//设fatherstatu为boolean类型值为true
@State fatherstatu:boolean = true
build() {
Row() {
Column() {
child({ childnum: $fathernum,childnum1:$fatherstatu})
}
.width('100%')
}
.height('100%')
}
}
子组件:
@Component
export struct child{ //导出
@Link childnum:number
@Link childnum1:boolean
build() {
Column({space:10}) {
//布尔类型:如果真执行,如果假则不执行;真假由childnum1的值决定
if(this.childnum1){
//进行字符的转换
Text(this.childnum.toString())
.fontSize(80)
.fontColor(Color.Red)
}
//设置一个按钮
Button('增加')
.width(200).height(90)
.fontSize(30)
//设置点击事件
.onClick(()=>{
// 每点击一次,childnum+1
this.childnum++
})
Button('减少')
.width(200).height(90)
.fontSize(30)
.onClick(()=>{
//点击后childnum的值减1
this.childnum--
})
Button('归零')
.width(200).height(90)
.fontSize(30)
.onClick(()=>{
// 点击之后归零
this.childnum = 0
})
Button('显示')
.width(200).height(90)
.fontSize(30)
.onClick(()=>{
//开关设置,也就是辨别真假
this.childnum1 =! this.childnum1
})
}
}
}