##HarmonyOS Next实战##HarmonyOS应用开发##教育##
目标:实现瀑布流图片和文字,并通过懒加载加载瀑布流子项。
实现思路:
- 创建Card模型
- 创建WaterFlowDataSource 数据源
- 定制WaterFlowItemComponent自定义组件
- 在页面实现WaterFlow和LazyForEach循环
WaterFlow
瀑布流容器,由“行”和“列”分割的单元格所组成,通过容器自身的排列规则,将不同大小的“项目”自上而下,如瀑布般紧密布局。
仅支持FlowItem子组件,支持渲染控制类型(if/else、ForEach、LazyForEach和Repeat)。
实战:
WaterFlowDataSource
// 实现IDataSource接口的对象,用于瀑布流组件加载数据
export class WaterFlowDataSource implements IDataSource {
private dataArray: Card[] = [];
private listeners: DataChangeListener[] = [];
constructor() {
this.dataArray.push({
image: $r('app.media.img_1'),
imageWidth: 162,
imageHeight: 130,
text: 'Ice cream is made with carrageenan …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_2'),
imageWidth: '100%',
imageHeight: 117,
text: 'Is makeup one of your daily esse …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_3'),
imageWidth: '100%',
imageHeight: 117,
text: 'Coffee is more than just a drink: It’s …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_4'),
imageWidth: 162,
imageHeight: 130,
text: 'Fashion is a popular style, especially in …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_5'),
imageWidth: '100%',
imageHeight: 206,
text: 'Argon is a great free UI packag …',
buttonLabel: 'View article'
});
}
// 获取索引对应的数据
public getData(index: number): Card {
return this.dataArray[index];
}
// 通知控制器数据重新加载
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);
})
}
//通知控制器数据批量修改
notifyDatasetChange(operations: DataOperation[]): void {
this.listeners.forEach(listener => {
listener.onDatasetChange(operations);
})
}
// 获取数据总数
public totalCount(): number {
return this.dataArray.length;
}
// 注册改变数据的控制器
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener);
}
}
// 注销改变数据的控制器
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1);
}
}
// 增加数据
public add1stItem(card: Card): void {
this.dataArray.splice(0, 0, card);
this.notifyDataAdd(0);
}
// 在数据尾部增加一个元素
public addLastItem(card: Card): void {
this.dataArray.splice(this.dataArray.length, 0, card);
this.notifyDataAdd(this.dataArray.length - 1);
}
public addDemoDataAtLast(): void {
this.dataArray.push({
image: $r('app.media.img_1'),
imageWidth: 162,
imageHeight: 130,
text: 'Ice cream is made with carrageenan …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_2'),
imageWidth: '100%',
imageHeight: 117,
text: 'Is makeup one of your daily esse …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_3'),
imageWidth: '100%',
imageHeight: 117,
text: 'Coffee is more than just a drink: It’s …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_4'),
imageWidth: 162,
imageHeight: 130,
text: 'Fashion is a popular style, especially in …',
buttonLabel: 'View article'
});
this.dataArray.push({
image: $r('app.media.img_5'),
imageWidth: '100%',
imageHeight: 206,
text: 'Argon is a great free UI packag …',
buttonLabel: 'View article'
});
}
// 在指定索引位置增加一个元素
public addItem(index: number, card: Card): void {
this.dataArray.splice(index, 0, card);
this.notifyDataAdd(index);
}
// 删除第一个元素
public delete1stItem(): void {
this.dataArray.splice(0, 1);
this.notifyDataDelete(0);
}
// 删除第二个元素
public delete2ndItem(): void {
this.dataArray.splice(1, 1);
this.notifyDataDelete(1);
}
// 删除最后一个元素
public deleteLastItem(): void {
this.dataArray.splice(-1, 1);
this.notifyDataDelete(this.dataArray.length);
}
// 在指定索引位置删除一个元素
public deleteItem(index: number): void {
this.dataArray.splice(index, 1);
this.notifyDataDelete(index);
}
// 重新加载数据
public reload(): void {
this.dataArray.splice(1, 1);
this.dataArray.splice(3, 2);
this.notifyDataReload();
}
}
export interface Card {
image: Resource //图片
imageWidth: Length //图片宽度
imageHeight: Length //图片高度
text: string //文字
buttonLabel: string //按钮文字
}
WaterFlowItemComponent
import { Card } from "./WaterFlowDataSource";
// @Reusable
@Component
export struct WaterFlowItemComponent {
@Prop item: Card
// 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容
aboutToReuse(params: Record<string, Card>) {
this.item = params.item;
console.info('Reuse item:' + JSON.stringify(this.item));
}
aboutToAppear() {
console.info('new item:' + JSON.stringify(this.item));
}
build() {
if (this.item.imageWidth == '100%') {
Column() {
Image(this.item.image)
.width(this.item.imageWidth)
.height(this.item.imageHeight)
Column() {
Text(this.item.text)
.fontWeight(400)
.fontColor('#32325D')
.fontSize(14)
.lineHeight(18)
Text(this.item.buttonLabel)
.fontWeight(700)
.fontColor('#5E72E4')
.fontSize(12)
.lineHeight(17)
}
.width('100%')
.padding(12)
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceBetween)
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Start)
} else {
Row() {
Image(this.item.image)
.width(this.item.imageWidth)
.height(this.item.imageHeight)
Column() {
Text(this.item.text)
.fontWeight(400)
.fontColor('#32325D')
.fontSize(14)
.lineHeight(18)
Text(this.item.buttonLabel)
.fontWeight(700)
.fontColor('#5E72E4')
.fontSize(12)
.lineHeight(17)
}
.height('100%')
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.padding(12)
.justifyContent(FlexAlign.SpaceBetween)
}
.width('100%')
.height('100%')
}
}
}
WaterFlowDemoPage
import { Card, WaterFlowDataSource } from './WaterFlowDataSource';
import { WaterFlowItemComponent } from './WaterFlowItemComponent';
@Entry
@Component
export struct WaterFlowDemoPage {
minSize: number = 80;
maxSize: number = 180;
fontSize: number = 24;
scroller: Scroller = new Scroller();
dataSource: WaterFlowDataSource = new WaterFlowDataSource();
dataCount: number = this.dataSource.totalCount();
private itemHeightArray: number[] = [];
@State sections: WaterFlowSections = new WaterFlowSections();
sectionMargin: Margin = {
top: 10,
left: 20,
bottom: 10,
right: 20
};
// 设置FlowItem的高度数组
setItemSizeArray() {
this.itemHeightArray.push(130);
this.itemHeightArray.push(212);
this.itemHeightArray.push(212);
this.itemHeightArray.push(130);
this.itemHeightArray.push(268);
}
aboutToAppear() {
this.setItemSizeArray();
this.addSectionOptions(true);
for (let index = 0; index < 10; index++) {
this.dataSource.addDemoDataAtLast();
this.setItemSizeArray();
this.addSectionOptions();
}
}
addSectionOptions(isFirstAdd: boolean = false) {
this.sections.push({
itemsCount: 1,
crossCount: 1,
margin: isFirstAdd ? {
top: 20,
left: 20,
bottom: 10,
right: 20
} : this.sectionMargin,
onGetItemMainSizeByIndex: (index: number) => {
return 130;
}
})
this.sections.push({
itemsCount: 2,
crossCount: 2,
rowsGap: '20vp',
margin: this.sectionMargin,
onGetItemMainSizeByIndex: (index: number) => {
return 212;
}
})
this.sections.push({
itemsCount: 1,
crossCount: 1,
margin: this.sectionMargin,
onGetItemMainSizeByIndex: (index: number) => {
return 130;
}
})
this.sections.push({
itemsCount: 1,
crossCount: 1,
rowsGap: '20vp',
columnsGap: '20vp',
margin: this.sectionMargin,
onGetItemMainSizeByIndex: (index: number) => {
return 268;
}
})
}
build() {
Column({ space: 2 }) {
WaterFlow({ scroller: this.scroller, sections: this.sections }) {
LazyForEach(this.dataSource, (item: Card, index: number) => {
FlowItem() {
WaterFlowItemComponent({ item: item })
}
.width('100%')
.backgroundColor(Color.White)
.borderRadius(6)
.clip(true)
}, (item: Card, index: number) => index.toString())
}
// .columnsTemplate('1fr 1fr') // 瀑布流使用sections参数时该属性无效
.columnsGap(14)
.rowsGap(20)
.backgroundColor('#F8F9FE')
.width('100%')
.height('100%')
.layoutWeight(1)
}
}
}
點擊查看更多內(nèi)容
為 TA 點贊
評論
評論
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章
正在加載中
感謝您的支持,我會繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦