#跟着若城学鸿蒙# 基于 List 的自定义下拉刷新组件(RefreshList)
·
下拉刷新是移动应用常用功能。虽然 ArkUI 自带 Refresh
组件,但在与 List
结合时往往难以满足定制化需求。本文以 RefreshList
为例,介绍如何手动处理触摸事件与滚动冲突,打造高可定制的下拉刷新控件。
1. 布局与插槽拆分
RefreshList
分为两部分:
- 刷新头(Header):位于可视区域上方,根据下拉距离动态显示提示。
- 内容区(Content):内部为
List
,展示数据项。
使用 @BuilderParam
让调用者传入 itemLayout
,自定义每个列表项:
@Component struct RefreshList {
@BuilderParam itemLayout?: (item: any, index: number) => void;
@Link dataSet: any[]; // 绑定数据
@Link refreshing: boolean; // 触发刷新标志
onRefresh?: () => void; // 刷新回调
@State offsetY: number = -this.headHeight;
private headHeight = 55;
private listScroller = new Scroller();
@Builder headLayout() {
/* 构建下拉提示头 */
}
build() {
Column() {
this.headLayout()
List({ scroller: this.listScroller }) {
ForEach(this.dataSet, (item, idx) => {
ListItem() {
this.itemLayout?.(item, idx);
}
.width("100%")
})
}
.onScrollFrameBegin(({ offsetRemain }) => ({ offsetRemain: this.listScrollable ? offsetRemain : 0 }))
.edgeEffect(EdgeEffect.None)
.width("100%").layoutWeight(1)
.position({ x: 0, y: this.offsetY + this.headHeight })
}
.width("100%").height("100%")
.clip(true)
.onTouch(this.handleTouch.bind(this))
}
private handleTouch(event: TouchEvent) { /* Down/Move/Up 逻辑 */ }
}
布局上,通过 position()
动态偏移内容区与头部。
2. 触摸与滚动冲突处理
-
在组件根
Column
上监听onTouch
:- Down:记录初始触点。
- Move:计算垂直位移
deltaY
,并在满足下拉条件时改变offsetY
,禁止内部List
滚动。 - Up:判断是否达临界点,触发
onRefresh()
并自动回弹或恢复到隐藏状态。
-
在
List
上使用.onScrollFrameBegin
:
当外层正拖动刷新时,返回offsetRemain = 0
使List
暂停滚动;拖动结束后恢复默认行为。
3. 数据与状态联动
@Link dataSet
:绑定外部数据数组,列表自动渲染。@Link refreshing
:由父组件控制刷新开始/结束,内部在监听器中对 UI 做对应动画和提示更新;onRefresh
回调在拖动到位时触发,外部可在该函数内异步拉取新数据,并在完成后将refreshing
置为false
。
4. 使用示例
import { RefreshList } from "./widget/refresh_list";
@Entry @Component struct Demo {
@State data: string[] = [];
@State refreshing: boolean = false;
@Builder itemLayout(item: any, idx: number) {
Text(`Item ${idx}: ${item}`)
.width("100%").height(80)
.textAlign(TextAlign.Center)
.backgroundColor('#bbccaa')
.margin({ top: 5 });
}
build() {
Column({ space: 10 }) {
Button("刷新数据").onClick(() => this.refreshing = true)
RefreshList({
dataSet: $data,
refreshing: $refreshing,
itemLayout: (i, idx) => this.itemLayout(i, idx),
onRefresh: () => this.fetchData()
})
}
}
aboutToAppear() { this.fetchData(); }
private fetchData() {
setTimeout(() => {
this.data = Array.from({ length: 20 }, (_, i) => (Math.random()*100).toFixed(2));
this.refreshing = false;
}, 2000);
}
}
通过上述步骤,你即可获得一个完全自定义、可插拔的下拉刷新列表控件,支持任意列表项渲染与交互反馈。
更多推荐
所有评论(0)