HarmonyOS Next 之列表上拉刷新下拉加载及其分页功能
2025-06-18 14:59:50
112次阅读
0个评论
在鸿蒙(HarmonyOSNEXT)应用开发中,上拉加载与下拉刷新是提升用户体验的重要功能。本文将详细介绍如何在鸿蒙应用中实现这一功能,包括设计思路、关键代码以及注意事项。
1. 组件化设计
为了保持代码的灵活性和可维护性,我们将上拉加载与下拉刷新功能封装成一个独立的组件。该组件可以无缝集成到任何需要这些功能的页面上,包括列表(List)、宫格(Grid)等多种布局。
2. 自定义扩展性
PullToRefresh是一款OpenHarmony环境下可用的下拉刷新、上拉加载组件。 支持设置内置动画的各种属性,支持设置自定义动画,支持lazyForEarch的数据作为数据源。。
3.完整源码
1.封装的组件 PullToRefresh.ets 代码如下:
import { PullToRefreshConfigurator } from './PullToRefreshConfigurator'
const IS_FREE = 0;
const IS_PULL_DOWN_1 = 11;
const IS_PULL_DOWN_2 = 12;
const IS_REFRESHING = 2;
const IS_REFRESHED = 3;
const IS_PULL_UP_1 = 41;
const IS_PULL_UP_2 = 42;
const IS_LOADING = 5;
@Component
export struct PullToRefresh {
@Link data: Object[];
scroller: Scroller = new Scroller();
@BuilderParam customList?: () => void;
refreshConfigurator?: PullToRefreshConfigurator;
mWidth?: Length = '100%';
mHeight?: Length = '100%';
onRefresh?: () => Promise<string> = () => {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('刷新失败');
}, 1000);
});
};
onLoadMore?: () => Promise<string> = () => {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('');
}, 1000);
});
};
// 自定义下拉动画
@BuilderParam customRefresh?: (() => void) | null;
//开启自定义下拉动画
onAnimPullDown?: (value?: number, width?: number, height?: number) => void;
onAnimRefreshing?: (value?: number, width?: number, height?: number) => void;
// 自定义上拉动画
@BuilderParam customLoad?: (() => void) | null;
onAnimPullUp?: (value?: number, width?: number, height?: number) => void;
onAnimLoading?: (value?: number, width?: number, height?: number) => void;
//-----------------------------以下为组件内自用属性-----------------------------//
@State private mHeightNumber?: number = 0;
@State private trYTop?: number = 0;
@State private trYBottom?: number = 0;
@State private state?: number = IS_FREE;
@State private refreshText?: string = '';
@State private loadText?: string = '';
@State private angle1?: number | string = 0;
@State private angle2?: number | string = 0;
private mWidthNumber?: number = 0;
private touchYOld?: number = 0;
private touchYNew?: number = 0;
private listOffsetOld?: number = 0;
private listOffsetNew?: number = 0;
private canvasSetting?: RenderingContextSettings = new RenderingContextSettings(true);
private canvasRefresh?: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.canvasSetting);
private value?: number = 0;
private timer?: number;
private refreshRingOx?: number = 0;
private refreshRingOy?: number = 0;
private refreshRingRadius?: number = 0;
private refreshPoint1x?: number = 0;
private refreshPoint1y?: number = 0;
private refreshPoint2x?: number = 0;
private refreshPoint2y?: number = 0;
private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Up | PanDirection.Down })
aboutToAppear() {
if (!this.refreshConfigurator) {
this.refreshConfigurator = new PullToRefreshConfigurator();
}
}
private initCanvas(): void {
if (this.refreshRingOx == 0) {
if (this.canvasRefresh !== undefined && this.refreshConfigurator !== undefined) {
this.canvasRefresh.strokeStyle = this.refreshConfigurator.getRefreshColor();
this.canvasRefresh.fillStyle = this.refreshConfigurator.getRefreshColor();
this.canvasRefresh.lineWidth = this.refreshConfigurator.getRefreshHeight() / 60 + 1;
}
if (this.refreshConfigurator !== undefined) {
this.refreshRingOx = this.refreshConfigurator.getRefreshWidth() / 2; // 圆心x坐标
this.refreshRingOy = this.refreshConfigurator.getRefreshHeight() / 2; // 圆心y坐标
this.refreshRingRadius = this.refreshConfigurator.getRefreshHeight() / 4; // 半径
this.refreshPoint1x = this.refreshRingOx + this.refreshRingRadius * Math.cos(Math.PI * 150 / 180);
this.refreshPoint1y = this.refreshRingOy + this.refreshRingRadius * Math.sin(Math.PI * 150 / 180);
this.refreshPoint2x = this.refreshRingOx + this.refreshRingRadius * Math.cos(Math.PI * -30 / 180);
this.refreshPoint2y = this.refreshRingOy + this.refreshRingRadius * Math.sin(Math.PI * -30 / 180);
}
}
}
build() {
Column() {
// 下拉刷新动画部分
Stack() {
this.headerUI()
}
.width('100%')
.height(this.trYTop !== undefined ? this.trYTop : 0)
.backgroundColor(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshBackgroundColor() : 0)
// 主体列表部分
Column() {
if (this.customList !== undefined) {
this.customList()
}
}
.width('100%')
.height((this.mHeightNumber !== undefined ? this.mHeightNumber : 0) - (this.trYTop !== undefined ? this.trYTop : 0) + (this.trYBottom !== undefined ? this.trYBottom : 0))
// 上拉加载动画部分
Stack() {
this.footerUI()
}
.width('100%')
.height(this.trYBottom !== undefined ? -this.trYBottom : 0)
.backgroundColor(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadBackgroundColor() : 0)
}
.width(this.mWidth === undefined ? '100%' : this.mWidth)
.height(this.mHeight === undefined ? '100%' : this.mHeight)
.onAreaChange((oldValue: Area, newValue: Area) => {
this.mWidthNumber = Math.round(newValue.width as number);
this.mHeightNumber = Math.round(newValue.height as number);
})
.parallelGesture(
PanGesture(this.panOption)
.onActionStart((event?: GestureEvent) => {
if (event !== undefined) {
this.touchYOld = event.offsetY;
}
})
.onActionUpdate((event?: GestureEvent) => {
if (event !== undefined) {
this.onActionUpdate(event);
}
})
.onActionEnd(() => {
this.onActionEnd();
})
)
}
@Builder
private headerUI() {
if (this.customRefresh !== undefined && this.customRefresh !== null) {
Column() {
this.customRefresh()
}
.width('100%')
.height('100%')
.visibility((this.state == IS_PULL_DOWN_1 || this.state == IS_PULL_DOWN_2 || this.state == IS_REFRESHING) ? Visibility.Visible : Visibility.Hidden)
} else {
Stack() {
Text(this.refreshText)
.textAlign(TextAlign.Center)
.fontColor(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshTextColor() : 0)
.fontSize(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshTextSize() : 0)
Stack() {
Canvas(this.canvasRefresh)
.width('100%')
.height('100%')
.onReady(() => {
this.initCanvas();
})
.visibility(this.state == IS_PULL_DOWN_2 ? Visibility.Visible : Visibility.Hidden)
LoadingProgress()
.width(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshHeight() : 0)
.height(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshHeight() : 0)
.color(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshColor() : 0)
.visibility(this.state == IS_REFRESHING ? Visibility.Visible : Visibility.Hidden)
}
.width(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshWidth() : 0)
.height(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getRefreshHeight() : 0)
}
.width('100%')
.height('100%')
}
}
@Builder
private footerUI() {
if (this.customLoad !== undefined && this.customLoad !== null) {
Column() {
this.customLoad()
}
.width('100%')
.height('100%')
.visibility((this.state == IS_PULL_UP_1 || this.state == IS_PULL_UP_2 || this.state == IS_LOADING ) ? Visibility.Visible : Visibility.Hidden)
} else {
Row() {
Stack() {
Image($r('app.media.icon_up'))
.width('100%')
.height('100%')
.objectFit(ImageFit.Contain)
.visibility(this.state == IS_PULL_UP_2 ? Visibility.Visible : Visibility.Hidden)
.rotate({
z: 1,
angle: this.angle1 !== undefined ? this.angle1 : 0
})
Image($r('app.media.icon_load'))
.width('100%')
.height('100%')
.objectFit(ImageFit.Contain)
.visibility(this.state == IS_LOADING ? Visibility.Visible : Visibility.Hidden)
.rotate({
z: 1,
angle: this.angle2 !== undefined ? this.angle2 : 0
})
}
.width(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadImgHeight() : 0)
.height(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadImgHeight() : 0)
Text(this.loadText)
.height('100%')
.textAlign(TextAlign.Center)
.margin({ left: 8 })
.fontColor(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadTextColor() : 0)
.fontSize(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadTextSize() : 0)
}
.height('100%')
}
}
private onActionUpdate(event: GestureEvent): void {
if (this.state !== undefined && this.refreshConfigurator !== undefined && this.touchYOld !== undefined) {
if (this.state == IS_FREE ||
this.state == IS_PULL_DOWN_1 || this.state == IS_PULL_DOWN_2 ||
this.state == IS_PULL_UP_1 || this.state == IS_PULL_UP_2) {
let maxTranslate = this.refreshConfigurator.getMaxTranslate()
let loadImgHeight = this.refreshConfigurator.getLoadImgHeight()
let refreshHeight = this.refreshConfigurator.getRefreshHeight()
if (!this.scroller.currentOffset()) {
return;
}
this.touchYNew = event.offsetY;
// 当前手势是否下拉
let distanceY = this.touchYNew - this.touchYOld;
let isPullAction = distanceY > 0;
//兼容页面滑动到顶部时,this.scroller.currentOffset().yOffset返回0.000000....的浮点数的情况
let yOffset: number = this.scroller.currentOffset().yOffset;
let isTop: boolean = yOffset == 0 ? true : false;
if (yOffset > -0.0001 && yOffset < 0.001) {
isTop = true;
}
if ((this.state == IS_FREE && isTop && isPullAction) || // 处于自由状态且列表处于顶部位置 并且 当前手势是下拉手势
this.state == IS_PULL_DOWN_1 || this.state == IS_PULL_DOWN_2) { // 处于下拉状态中
if (this.refreshConfigurator.getHasRefresh()) {
if (this.touchYOld !== undefined && refreshHeight !== undefined) {
// 获取最新位移距离
let trY = this.touchYNew - this.touchYOld;
//防止下拉回滑时list组件底层跟着滑动
if(trY < 0) {
this.scroller.scrollTo({xOffset: 0, yOffset: 0})
}
// 计算当前需要位移的总距离
this.trYTop = this.getTranslateYOfRefresh(trY);
if (this.trYTop < refreshHeight) {
this.state = IS_PULL_DOWN_1;
} else {
this.state = IS_PULL_DOWN_2;
}
// 如果没有自定义刷新动画,就执行内置动画下拉时的逻辑
if (!this.customRefresh && maxTranslate !== undefined) {
this.drawRefreshView(this.trYTop / maxTranslate);
}
// 如果有下拉中动画回调,就执行下拉中动画回调
if (this.onAnimPullDown && maxTranslate !== undefined) {
this.onAnimPullDown(this.trYTop / maxTranslate, this.mWidthNumber, this.trYTop);
}
}
}
} else if (this.refreshConfigurator.getHasLoadMore()) {
this.listOffsetNew = this.scroller.currentOffset().yOffset;
// 列表处于底部位置且上滑时,2.已上滑时
try {
if (this.touchYOld !== undefined) {
if ((this.state == IS_FREE && this.listOffsetOld == this.listOffsetNew && this.listOffsetOld != 0 && this.touchYNew < this.touchYOld && this.scroller.isAtEnd()) ||
this.state == IS_PULL_UP_1 || this.state == IS_PULL_UP_2) {
// 获取最新的位移距离
let trY = this.touchYNew - this.touchYOld;
// 计算当前需要位移的总距离
this.trYBottom = this.getTranslateYOfLoadMore(trY);
if (loadImgHeight !== undefined && this.trYBottom > -loadImgHeight) {
this.state = IS_PULL_UP_1;
} else {
this.state = IS_PULL_UP_2;
}
// 如果没有自定义加载更多动画,就执行内置动画上拉时的逻辑
if (!this.customLoad && maxTranslate !== undefined) {
this.drawLoadView(true, -this.trYBottom / maxTranslate);
}
// 如果有上拉中动画回调,就执行上拉中动画回调
if (this.onAnimPullUp) {
if (this.trYBottom !== undefined && maxTranslate !== undefined) {
this.onAnimPullUp(-this.trYBottom / maxTranslate, this.mWidthNumber, -this.trYBottom);
}
}
}
}
} catch (error) {
if (this.touchYOld !== undefined) {
if ((this.state == IS_FREE && this.listOffsetOld == this.listOffsetNew && this.listOffsetOld != 0 && this.touchYNew < this.touchYOld) ||
this.state == IS_PULL_UP_1 || this.state == IS_PULL_UP_2) {
if (this.touchYNew !== undefined && this.touchYOld !== undefined && loadImgHeight !== undefined) {
// 获取最新的位移距离
let trY = this.touchYNew - this.touchYOld;
// 计算当前需要位移的总距离
this.trYBottom = this.getTranslateYOfLoadMore(trY);
if (this.trYBottom > -loadImgHeight) {
this.state = IS_PULL_UP_1;
} else {
this.state = IS_PULL_UP_2;
}
// 如果没有自定义加载更多动画,就执行内置动画上拉时的逻辑
if (!this.customLoad && maxTranslate !== undefined) {
this.drawLoadView(true, -this.trYBottom / maxTranslate);
}
// 如果有上拉中动画回调,就执行上拉中动画回调
if (this.onAnimPullUp) {
if (this.trYBottom !== undefined && maxTranslate !== undefined) {
this.onAnimPullUp(-this.trYBottom / maxTranslate, this.mWidthNumber, -this.trYBottom);
}
}
}
}
}
}
this.listOffsetOld = this.listOffsetNew;
}
this.touchYOld = this.touchYNew;
}
}
}
private onActionEnd(): void {
if (this.refreshConfigurator !== undefined) {
let maxTranslate = this.refreshConfigurator.getMaxTranslate()
let refreshAnimDuration = this.refreshConfigurator.getRefreshAnimDuration();
if (this.refreshConfigurator.getListIsPlacement()) {
if (this.state !== undefined) {
if (this.state == IS_PULL_DOWN_1 || this.state == IS_PULL_DOWN_2) {
// 让列表归位到顶部
this.scroller.scrollEdge(Edge.Top);
// 让列表归位到底部
} else if (this.state == IS_PULL_UP_1 || this.state == IS_PULL_UP_2) {
this.scroller.scrollEdge(Edge.Bottom);
}
}
}
if (this.trYTop !== undefined) {
if (this.trYTop > 0) { // 下拉结束
if (this.state !== undefined && maxTranslate !== undefined) {
if (this.state == IS_FREE || this.state == IS_PULL_DOWN_1 || this.state == IS_PULL_DOWN_2) {
if (this.trYTop / maxTranslate < 0.75) {
this.closeRefresh();
} else {
this.state = IS_REFRESHING;
this.trYTop = maxTranslate * 0.75;
clearInterval(this.timer);
this.timer = setInterval(() => {
if (this.value !== undefined) {
if (this.value >= 1) {
this.value -= 1;
} else {
if (refreshAnimDuration !== undefined && refreshAnimDuration !== 0) {
this.value += 10 / refreshAnimDuration;
}
}
// 保留3位小数
this.value = Math.round(this.value * 1000) / 1000;
}
// 刷新中动画采用系统组件,因此不用自己去执行动画
// 如果有刷新中动画回调,就执行刷新中动画回调
if (this.onAnimRefreshing) {
this.onAnimRefreshing(this.value, this.mWidthNumber, this.trYTop);
}
}, 10);
if (this.onRefresh !== undefined) {
this.onRefresh().then((refreshText) => {
if (refreshText.length == 0) {
this.closeRefresh();
} else {
this.state = IS_REFRESHED;
if (!this.customRefresh) {
this.refreshText = refreshText;
}
setTimeout(() => {
this.closeRefresh();
}, 1000);
}
});
}
}
}
}
} else if (this.trYBottom !== undefined && this.trYBottom < 0) { // 上拉结束
if (this.state !== undefined && maxTranslate !== undefined) {
if (this.state == IS_FREE || this.state == IS_PULL_UP_1 || this.state == IS_PULL_UP_2) {
if (-this.trYBottom / maxTranslate < 0.75) {
this.closeLoad();
} else {
this.state = IS_LOADING;
this.trYBottom = -maxTranslate * 0.75;
clearInterval(this.timer);
this.timer = setInterval(() => {
if (this.value !== undefined) {
if (this.value >= 1) {
this.value -= 1;
} else {
this.value += 0.01;
}
// 保留2位小数
this.value = Math.round(this.value * 100) / 100;
// 如果没有自定义加载中动画,就执行内置加载中动画
if (!this.customLoad) {
this.drawLoadView(false, this.value);
}
}
// 如果有加载中动画回调,就执行加载中动画回调
if (this.onAnimLoading) {
if (this.trYBottom !== undefined) {
this.onAnimLoading(this.value, this.mWidthNumber, -this.trYBottom);
}
}
}, 10);
if (this.onLoadMore !== undefined) {
this.onLoadMore().then((loadText) => {
this.closeLoad();
});
}
}
}
}
} else {
this.state = IS_FREE;
}
}
}
}
private getTranslateYOfRefresh(newTranslateY: number): number {
if (this.refreshConfigurator !== undefined) {
let maxTranslateY = this.refreshConfigurator.getMaxTranslate();
let sensitivity = this.refreshConfigurator.getSensitivity();
if (maxTranslateY !== undefined && sensitivity !== undefined && this.trYTop !== undefined) {
// 阻尼值计算
if (this.trYTop / maxTranslateY < 0.2) {
newTranslateY = newTranslateY * 1 * sensitivity;
} else if (this.trYTop / maxTranslateY < 0.4) {
newTranslateY = newTranslateY * 0.8 * sensitivity;
} else if (this.trYTop / maxTranslateY < 0.6) {
newTranslateY = newTranslateY * 0.6 * sensitivity;
} else if (this.trYTop / maxTranslateY < 0.8) {
newTranslateY = newTranslateY * 0.4 * sensitivity;
} else {
newTranslateY = newTranslateY * 0.2 * sensitivity;
}
// 下拉值计算
if (this.trYTop + newTranslateY > maxTranslateY) {
return maxTranslateY;
} else if (this.trYTop + newTranslateY < 0) {
return 0;
} else {
return this.trYTop + newTranslateY;
}
}
}
return 0;
}
private getTranslateYOfLoadMore(newTranslateY: number): number {
if (this.refreshConfigurator !== undefined) {
let maxTranslateY = this.refreshConfigurator.getMaxTranslate();
let sensitivity = this.refreshConfigurator.getSensitivity();
if (maxTranslateY !== undefined && sensitivity !== undefined && this.trYBottom !== undefined) {
// 阻尼值计算
if (this.trYBottom / maxTranslateY > -0.2) {
newTranslateY = newTranslateY * 1 * sensitivity;
} else if (this.trYBottom / maxTranslateY > -0.4) {
newTranslateY = newTranslateY * 0.8 * sensitivity;
} else if (this.trYBottom / maxTranslateY > -0.6) {
newTranslateY = newTranslateY * 0.6 * sensitivity;
} else if (this.trYBottom / maxTranslateY > -0.8) {
newTranslateY = newTranslateY * 0.4 * sensitivity;
} else {
newTranslateY = newTranslateY * 0.2 * sensitivity;
}
// 下拉值计算
if (this.trYBottom + newTranslateY < -maxTranslateY) {
return -maxTranslateY;
} else if (this.trYBottom + newTranslateY > 0) {
return 0;
} else {
return this.trYBottom + newTranslateY;
}
}
}
return 0;
}
private drawRefreshView(value: number): void {
if (this.refreshConfigurator !== undefined && this.trYTop !== undefined) {
let refreshHeight = this.refreshConfigurator.getRefreshHeight()
if (refreshHeight !== undefined && this.trYTop >= refreshHeight) {
if (this.canvasRefresh !== undefined) {
let refreshWidth = this.refreshConfigurator.getRefreshWidth()
if (refreshWidth !== undefined) {
this.canvasRefresh.clearRect(0, 0, refreshWidth, refreshHeight);
}
// 绘制圆环
this.canvasRefresh.beginPath();
if (this.refreshRingOx !== undefined && this.refreshRingOy !== undefined && this.refreshRingRadius !== undefined) {
this.canvasRefresh.arc(this.refreshRingOx, this.refreshRingOy, this.refreshRingRadius, 0, Math.PI * 2);
}
this.canvasRefresh.stroke();
// 绘制卫星
value = value > 0.75 ? 0.75 : value;
this.canvasRefresh.beginPath();
if (this.refreshPoint2x !== undefined && this.refreshPoint1x !== undefined
&& this.refreshPoint2y !== undefined && this.refreshPoint1y !== undefined) {
this.canvasRefresh.arc(
value * (this.refreshPoint2x - this.refreshPoint1x) + this.refreshPoint1x,
value * (this.refreshPoint2y - this.refreshPoint1y) + this.refreshPoint1y,
refreshHeight / 20 + 1, 0, Math.PI * 2);
}
this.canvasRefresh.fill();
}
}
}
}
private drawLoadView(isPullUp: boolean, value: number): void {
if (isPullUp) {
if (this.refreshConfigurator !== undefined) {
let loadImgHeight = this.refreshConfigurator.getLoadImgHeight()
if (loadImgHeight !== undefined && this.trYBottom !== undefined) {
if (this.trYBottom <= -loadImgHeight) {
if (value < 0.75) {
this.angle1 = 0;
if (this.refreshConfigurator !== undefined) {
this.loadText = this.refreshConfigurator.getLoadTextPullUp1();
}
} else {
this.angle1 = 180;
if (this.refreshConfigurator !== undefined) {
this.loadText = this.refreshConfigurator.getLoadTextPullUp2();
}
}
} else {
this.loadText = '';
}
}
}
} else {
this.angle2 = value * 360;
if (this.refreshConfigurator !== undefined) {
this.loadText = this.refreshConfigurator.getLoadTextLoading();
}
}
}
public closeRefresh(): void {
clearInterval(this.timer);
if (this.refreshConfigurator !== undefined) {
animateTo({ duration: this.refreshConfigurator.getAnimDuration() }, () => {
this.trYTop = 0;
});
}
if (this.refreshConfigurator !== undefined) {
setTimeout(() => {
this.state = IS_FREE;
this.refreshText = '';
}, this.refreshConfigurator.getAnimDuration());
}
}
public closeLoad(): void {
clearInterval(this.timer);
if (this.refreshConfigurator !== undefined) {
animateTo({ duration: this.refreshConfigurator.getAnimDuration() }, () => {
this.trYBottom = 0;
});
}
this.state = IS_FREE;
this.loadText = '';
}
}
配置文件:PullToRefreshConfigurator.ets
export class PullToRefreshConfigurator {
private hasRefresh?: boolean = true; // 是否具有下拉刷新功能
private hasLoadMore?: boolean = true; // 是否具有上拉加载功能
private maxTranslate?: number = 100; // 可下拉上拉的最大距离
private sensitivity?: number = 0.7; // 下拉上拉灵敏度
private listIsPlacement?: boolean = true; // 滑动结束后列表是否归位
private animDuration?: number = 150; // 滑动结束后,回弹动画执行时间
private refreshHeight?: number = 30; // 下拉动画高度
private refreshColor?: string = '#999999'; // 下拉动画颜色
private refreshBackgroundColor?: ResourceColor = 'rgba(0,0,0,0)'; // 下拉动画区域背景色
private refreshTextColor?: ResourceColor = '#999999'; // 下拉加载完毕后提示文本的字体颜色
private refreshTextSize?: number | string | Resource = 18; // 下拉加载完毕后提示文本的字体大小
private refreshAnimDuration?: number = 1000; // 下拉动画执行一次的时间
private loadImgHeight?: number = 30; // 上拉图片高度
private loadBackgroundColor?: ResourceColor = 'rgba(0,0,0,0)'; // 上拉动画区域背景色
private loadTextColor?: ResourceColor = '#999999'; // 上拉文本的字体颜色
private loadTextSize?: number | string | Resource = 18; // 上拉文本的字体大小
private loadTextPullUp1?: string = '正在上拉刷新...'; // 上拉1阶段文本
private loadTextPullUp2?: string = '放开刷新'; // 上拉2阶段文本
private loadTextLoading?: string = '正在玩命加载中...'; // 上拉加载更多中时的文本
setHasRefresh(hasRefresh: boolean) {
this.hasRefresh = hasRefresh;
return this;
}
getHasRefresh() {
return this.hasRefresh;
}
setHasLoadMore(hasLoadMore: boolean) {
this.hasLoadMore = hasLoadMore;
return this;
}
getHasLoadMore() {
return this.hasLoadMore;
}
setMaxTranslate(maxTranslate: number) {
this.maxTranslate = maxTranslate;
return this;
}
getMaxTranslate() {
return this.maxTranslate;
}
setSensitivity(sensitivity: number) {
this.sensitivity = sensitivity;
return this;
}
getSensitivity() {
return this.sensitivity;
}
setListIsPlacement(listIsPlacement: boolean) {
this.listIsPlacement = listIsPlacement;
return this;
}
getListIsPlacement() {
return this.listIsPlacement;
}
setAnimDuration(animDuration: number) {
this.animDuration = animDuration;
return this;
}
getAnimDuration() {
return this.animDuration;
}
getRefreshWidth(): number {
if (this.refreshHeight !== undefined) {
return this.refreshHeight / 3 * 4;
}
return 0;
}
setRefreshHeight(refreshHeight: number) {
this.refreshHeight = refreshHeight;
return this;
}
getRefreshHeight(): number {
return this.refreshHeight !== undefined ? this.refreshHeight : 0;
}
setRefreshColor(refreshColor: string) {
this.refreshColor = refreshColor;
return this;
}
getRefreshColor(): string {
return this.refreshColor !== undefined ? this.refreshColor : "0";
}
setRefreshBackgroundColor(refreshBackgroundColor: ResourceColor) {
this.refreshBackgroundColor = refreshBackgroundColor;
return this;
}
getRefreshBackgroundColor(): ResourceColor {
return this.refreshBackgroundColor !== undefined ? this.refreshBackgroundColor : 0;
}
setRefreshTextColor(refreshTextColor: ResourceColor) {
this.refreshTextColor = refreshTextColor;
return this;
}
getRefreshTextColor(): ResourceColor {
return this.refreshTextColor !== undefined ? this.refreshTextColor : 0;
}
setRefreshTextSize(refreshTextSize: number | string | Resource) {
this.refreshTextSize = refreshTextSize;
return this;
}
getRefreshTextSize(): number | string | Resource {
return this.refreshTextSize !== undefined ? this.refreshTextSize : 0;
}
setRefreshAnimDuration(refreshAnimDuration: number) {
this.refreshAnimDuration = refreshAnimDuration;
return this;
}
getRefreshAnimDuration() {
return this.refreshAnimDuration;
}
setLoadImgHeight(loadImgHeight: number) {
this.loadImgHeight = loadImgHeight;
return this;
}
getLoadImgHeight(): number {
return this.loadImgHeight !== undefined ? this.loadImgHeight : 0;
}
setLoadBackgroundColor(loadBackgroundColor: ResourceColor) {
this.loadBackgroundColor = loadBackgroundColor;
return this;
}
getLoadBackgroundColor(): ResourceColor {
if (this.loadBackgroundColor !== undefined) {
return this.loadBackgroundColor;
}
return 0;
}
setLoadTextColor(loadTextColor: ResourceColor) {
this.loadTextColor = loadTextColor;
return this;
}
getLoadTextColor(): ResourceColor {
if (this.loadTextColor !== undefined) {
return this.loadTextColor;
}
return 0;
}
setLoadTextSize(loadTextSize: number | string | Resource) {
this.loadTextSize = loadTextSize;
return this;
}
getLoadTextSize(): number | string | Resource {
if (this.loadTextSize !== undefined) {
return this.loadTextSize;
}
return 0;
}
setLoadTextPullUp1(loadTextPullUp1: string) {
this.loadTextPullUp1 = loadTextPullUp1;
return this;
}
getLoadTextPullUp1() {
return this.loadTextPullUp1;
}
setLoadTextPullUp2(loadTextPullUp2: string) {
this.loadTextPullUp2 = loadTextPullUp2;
return this;
}
getLoadTextPullUp2() {
return this.loadTextPullUp2;
}
setLoadTextLoading(loadTextLoading: string) {
this.loadTextLoading = loadTextLoading;
return this;
}
getLoadTextLoading(): string {
return this.loadTextLoading !== undefined ? this.loadTextLoading : "";
}
}
使用案例如下:
import { PullToRefresh } from '../pulltorefresh';
build() {
// 上拉加载 下拉刷新组件
// 需绑定列表或宫格组件
private scroller: Scroller = new Scroller();
PullToRefresh({
// 必传项,列表组件所绑定的数据
data: $data,
// 必传项,需绑定传入主体布局内的列表或宫格组件
scroller: this.scroller,
// 必传项,自定义主体布局,内部有列表或宫格组件
customList: () => {
// 一个用@Builder修饰过的UI方法
this.getListView();
},
// 可选项,下拉刷新回调
onRefresh: () => {
return new Promise<string>((resolve, reject) => {
// 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
setTimeout(() => {
resolve('刷新成功');
this.data = this.dataNumbers;
}, 2000);
});
},
// 可选项,上拉加载更多回调
onLoadMore: () => {
return new Promise<string>((resolve, reject) => {
// 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
setTimeout(() => {
resolve('');
this.data.push("增加的条目" + this.data.length);
}, 2000);
});
},
customLoad: null,
customRefresh: null,
})
}
// 自定义列表里面的组件内容
@Builder
private getListView() {
Stack({ alignContent: Alignment.BottomEnd }) {
List({ space: CommonConstants.LIST_SPACE, scroller: this.scroller }) {
LazyForEach(this.listData, (item: listData) => {
ListItem() {
listItem({
//listTitle: item.listTitle,
//listContent: item.listContent,
//listTime: item.listTime,
//listImage: item.listImage,
//listParams: new listParamsClass(item.listParams?.parameter, item.listParams?.router as string, item.listParams?.marker as string, item.listParams?.location as string)
})
}
.backgroundColor($r('app.color.listViewColor'))
.margin({
bottom: $r('app.string.list_list_margin_bottom'),
})
.borderRadius($r('app.integer.list_list_border_radius'))
}, (item: listData, index?: number) => JSON.stringify(item) + index);
}
.onScrollIndex((first: number) => {
this.firstIndex = first;
})
.width($r('app.string.list_List_width'))
.backgroundColor($r('app.color.listColor'))
.edgeEffect(EdgeEffect.None)
Row() {
Image($r('app.media.ic_public_backtotop'))
.width($r('app.integer.back_top_img_size'))
.height($r('app.integer.back_top_img_size'))
.opacity($r('app.float.jump_button_opacity'))
}
.onClick(() => {
// if (this.firstIndex >= this.SWITCH_BUTTON) {
// this.scroller.scrollTo({
// xOffset: CommonConstants.ZERO,
// yOffset: CommonConstants.ZERO,
// animation: { duration: this.ANIMATION_DURATION, curve: Curve.LinearOutSlowIn }
// });
// }
})
.visibility(this.firstIndex >= this.SWITCH_BUTTON ? Visibility.Visible : Visibility.None)
.justifyContent(FlexAlign.Center)
.width($r('app.integer.back_top_img_background_size'))
.height($r('app.integer.back_top_img_background_size'))
.backgroundColor($r("app.color.tab_sel_color"))
.borderRadius($r('app.integer.back_top_bag_radius'))
.margin({
right: new BreakpointType($r('app.float.page_col_padding_sm'), $r('app.float.page_col_padding_md'),
$r('app.float.page_col_padding_lg')).getValue(this.currentBreakpoint),
bottom: $r('app.integer.back_top_margin')
})
}
}
00
- 0回答
- 0粉丝
- 1关注
相关话题
- 自定义组件之<九>自定义下拉刷新上拉加载(RefreshLayout)
- HarmonyOS应用开发实战:半天实现知乎日报项目(七、知乎日报List列表下拉刷新及上滑加载更多分页的实现)
- 鸿蒙开发:一个轻盈的上拉下拉刷新组件
- 127.HarmonyOS NEXT 数字滚动示例详解(二):下拉刷新实现
- Scroll、Refresh、List 三件套打造互动式下拉刷新的滚动列表
- 162.HarmonyOS NEXT系列教程之列表交换组件删除功能实现
- 自定义组件之<八>自定义下拉刷新(RefreshList)
- 161.HarmonyOS NEXT系列教程之列表交换组件列表项交互实现
- 176.HarmonyOS NEXT系列教程之列表交换组件列表项操作实现
- [HarmonyOS NEXT 实战案例二] 新闻资讯网格列表(上)
- [HarmonyOS NEXT 实战案例十七] 设置选项列表网格布局(上)
- 169.HarmonyOS NEXT系列教程之列表交换组件开发总结
- 159.HarmonyOS NEXT系列教程之列表交换组件架构设计
- 165.HarmonyOS NEXT系列教程之列表交换组件Mock数据设计
- 166.HarmonyOS NEXT系列教程之列表交换组件性能优化实现