HarmonyOS 鸿蒙Next中List组件在滚动到顶部时如何实现“下拉刷新”动画?
HarmonyOS 鸿蒙Next中List组件在滚动到顶部时如何实现“下拉刷新”动画? 想实现类似微信的下拉刷新,带箭头旋转和文字提示。ArkUI 有内置支持吗?
【背景知识】
- Refresh是用于下拉刷新并显示动效的容器组件,入参RefreshOptions包含参数builder或refreshingContent,二者都是用于设置自定义刷新区域的显示内容,不可同时使用。builder参数的类型为CustomBuilder,结合@Builder自定义构建函数使用,refreshingContent参数的类型为ComponentContent,有关使用规格参考BuilderNode。这两个参数在Refresh中的使用可参考示例3(自定义刷新区域显示内容-builder)和示例4(自定义刷新区域显示内容-refreshingContent)。
- ComponentContent是组件内容的实体封装,其对象支持在非UI组件中创建与传递。使用时需要创建对应节点所需的UI上下文UIContext和WrappedBuilder封装的builder函数。
【解决方案】
开发者可以直接使用Refresh实现刷新,也可以通过设置自定义刷新区域显示内容,实现带箭头旋转和文字提示:
import { ComponentContent } from '@ohos.arkui.node';
const PULL_REFRESHING = '刷新中...';
@Entry
@Component
struct MainTab {
@Builder
barBars() {
Text('BAR').margin({ top: 20, bottom: 20 }).fontSize(18).fontWeight('bold');
}
@Builder
barContents() {
Tabs() {
TabContent() {
RefreshExample();
};
}
.layoutWeight(1)
.width('100%')
.barHeight(0)
.barMode(BarMode.Scrollable)
.barOverlap(false)
.fadingEdge(false);
}
build() {
Column() {
TopSvBar({
bars: this.barBars,
content: this.barContents
});
}.width('100%').height('100%');
}
}
@Component
struct TopSvBar {
@BuilderParam bars: () => void = this.barContents;
@BuilderParam content: () => void = this.barContents;
@Builder
barContents() {
}
build() {
Column() {
Text('标题').margin({ top: 20, bottom: 20 }).fontSize(18).fontWeight('bold');
Column() {
this.bars();
}.height(50);
Column() {
this.content();
}.layoutWeight(1);
};
}
}
class Params {
angle: number = 0;
constructor(angle: number) {
this.angle = angle;
}
}
@Builder
function customRefreshingContent(params: Params) {
Row() {
Text(){
SymbolSpan($r('sys.symbol.arrow_clockwise'))
.fontWeight(FontWeight.Lighter)
.fontSize(20)
}
.rotate({ angle: params.angle })
.width(20)
.height(20);
Text('刷新中').fontSize(16).margin({ left: 20 });
}
.alignItems(VerticalAlign.Center)
.width('100%')
.justifyContent(FlexAlign.Center)
.constraintSize({ minHeight: 32 });
}
@Component
struct RefreshExample {
@State isRefreshing: boolean = false;
@State refreshString: string = '下拉刷新';
private contentNode?: ComponentContent<Object> = undefined;
private params: Params = new Params(0);
maxRefreshingHeight: number = 200.0;
@State ratio: number = 1;
@State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
colors: [ResourceColor | LinearGradient, number][] = []; // 组件进度条颜色配置
// 设置进度条颜色
setColors(percentage: number) {
this.colors = [['#FF585E70', percentage], ['#ffffff', 1 - percentage]];
}
@State @Watch('valueChange') currentValue: number = 0; // 当前值
// 计算当前值占总的百分比
getPercentage(): number {
return Math.min(this.currentValue / 100, 1);
}
// 当前值改变监听
valueChange() {
this.setColors(this.getPercentage());
}
aboutToAppear(): void {
let uiContext = this.getUIContext();
this.contentNode = new ComponentContent(uiContext, wrapBuilder(customRefreshingContent), this.params);
}
build() {
Column() {
Refresh({ refreshing: $$this.isRefreshing, refreshingContent: this.contentNode }) {
List() {
ForEach(this.arr, (item: string) => {
ListItem() {
Text('' + item)
.width('70%')
.height(80)
.fontSize(16)
.margin(10)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF);
};
}, (item: string) => item);
}
.onScrollIndex((first: number) => {
console.info(first.toString());
})
.width('100%')
.height('100%')
.alignListItem(ListItemAlign.Center)
.scrollBar(BarState.Off);
}
.pullDownRatio(this.ratio)
.backgroundColor(0x89CFF0)
.pullToRefresh(true)
.refreshOffset(64)
.onOffsetChange((offset: number) => {
// 越接近最大距离,下拉跟手系数越小
this.ratio = 1 - Math.pow((offset / this.maxRefreshingHeight), 3);
})
.onStateChange((refreshStatus: RefreshStatus) => {
if (refreshStatus === 3) {
this.refreshString = PULL_REFRESHING;
this.getUIContext().animateTo({ curve: Curve.Linear, iterations: 5, duration: 1000 }, () => {
this.params.angle = 360;
// 更新自定义组件内容
this.contentNode?.update(this.params);
});
}
})
.onRefreshing(() => {
setTimeout(() => {
this.isRefreshing = false;
this.contentNode?.update(this.params.angle = 0);
}, 5000);
console.info('onRefreshing test');
});
};
}
}
更多关于HarmonyOS 鸿蒙Next中List组件在滚动到顶部时如何实现“下拉刷新”动画?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
这种下拉刷新没必要自己实现,重复造轮子了。
OpenHarmony三方库中心仓 可以从三分库里面直接搜。
有
参考代码如下:
// xxx.ets
@Entry
@Component
struct RefreshExample {
@State isRefreshing: boolean = false;
@State promptText: string = "Refreshing...";
@State arr: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
build() {
Column() {
Refresh({ refreshing: $$this.isRefreshing, promptText: this.promptText }) {
List() {
ForEach(this.arr, (item: string) => {
ListItem() {
Text(item)
.width('70%')
.height(80)
.fontSize(16)
.margin(10)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}
}, (item: string) => item)
}
.onScrollIndex((first: number) => {
console.info(first.toString());
})
.width('100%')
.height('100%')
.alignListItem(ListItemAlign.Center)
.scrollBar(BarState.Off)
}
.backgroundColor(0x89CFF0)
.pullToRefresh(true)
.refreshOffset(96)
.onStateChange((refreshStatus: RefreshStatus) => {
console.info('Refresh onStatueChange state is ' + refreshStatus);
})
.onOffsetChange((value: number) => {
console.info('Refresh onOffsetChange offset:' + value);
})
.onRefreshing(() => {
setTimeout(() => {
this.isRefreshing = false;
}, 2000)
console.info('onRefreshing test');
})
}
}
}
效果如图:

可以参考文档 List组件 - 下拉刷新与上拉加载
建议根据 Codelabs 中的 实现新闻数据加载功能 - 6.下拉刷新 作为示例代码参考依据。
Refresh 可以进行页面下拉操作并显示刷新动效的容器组件。
通过builder参数自定义刷新区域显示内容。可根据onStateChange回调参数RefreshStatus,在下拉过程中改变箭头方向和文字提示,以及刷新中动效。
// xxx.ets
@Entry
@Component
struct RefreshExample {
@State isRefreshing: boolean = false;
@State arr: String[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
@Builder
customRefreshComponent() {
Stack() {
Row() {
LoadingProgress().height(32)
Text("Refreshing...").fontSize(16).margin({ left: 20 })
}
.alignItems(VerticalAlign.Center)
}
.align(Alignment.Center)
.clip(true)
// 设置最小高度约束保证自定义组件高度随刷新区域高度变化时自定义组件高度不会低于minHeight。
.constraintSize({ minHeight: 32 })
.width("100%")
}
build() {
Column() {
Refresh({ refreshing: $$this.isRefreshing, builder: this.customRefreshComponent() }) {
List() {
ForEach(this.arr, (item: string) => {
ListItem() {
Text('' + item)
.width('70%')
.height(80)
.fontSize(16)
.margin(10)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}
}, (item: string) => item)
}
.onScrollIndex((first: number) => {
console.info(first.toString());
})
.width('100%')
.height('100%')
.alignListItem(ListItemAlign.Center)
.scrollBar(BarState.Off)
}
.backgroundColor(0x89CFF0)
.pullToRefresh(true)
.refreshOffset(64)
.onStateChange((refreshStatus: RefreshStatus) => {
console.info('Refresh onStatueChange state is ' + refreshStatus);
})
.onRefreshing(() => {
setTimeout(() => {
this.isRefreshing = false;
}, 2000)
console.info('onRefreshing test');
})
}
}
}
你想找的是这个:Refresh,里面有实例可以直接用
在HarmonyOS Next中,List组件实现下拉刷新动画需使用@State装饰器管理刷新状态,结合onTouch事件监听手势。通过if条件渲染自定义刷新组件(如Refresh),利用scrollToIndex方法滚动到顶部时触发动画。动画效果可使用animateTo方法实现平滑过渡。
在HarmonyOS Next的ArkUI中,可以通过Refresh组件实现下拉刷新功能,它内置了拉动提示、刷新动画等能力。
核心实现步骤:
- 使用
Refresh组件包裹列表:将List组件作为Refresh的子组件。 - 配置刷新参数:
onRefresh:触发刷新时的回调函数。offset:刷新触发距离(默认值16vp)。refreshType:设置刷新组件类型,PullDown(默认)即为下拉刷新。
- 自定义刷新UI:通过
builder属性自定义刷新过程中的提示内容(如箭头图标、文字)。
示例代码:
@Entry
@Component
struct RefreshExample {
@State isRefreshing: boolean = false
@State dataArray: string[] = ['Item 1', 'Item 2', 'Item 3']
build() {
Column() {
Refresh({
onRefresh: () => {
this.isRefreshing = true
// 模拟网络请求
setTimeout(() => {
this.dataArray.unshift('New Item')
this.isRefreshing = false
}, 2000)
},
offset: 120,
builder: (refreshState: RefreshStatus, percent: number) => {
this.CustomRefreshUI(refreshState, percent)
}
}) {
List() {
ForEach(this.dataArray, (item: string) => {
ListItem() {
Text(item).padding(20)
}
})
}
}
}
}
@Builder
CustomRefreshUI(refreshState: RefreshStatus, percent: number) {
Column() {
if (refreshState === RefreshStatus.Inactive) {
Image($r('app.media.arrow_down'))
.rotate({ angle: 0 })
Text('下拉刷新')
} else if (refreshState === RefreshStatus.Drag) {
Image($r('app.media.arrow_down'))
.rotate({ angle: percent >= 1.0 ? 180 : 0 }) // 到达阈值时箭头翻转
Text(percent >= 1.0 ? '释放立即刷新' : '继续下拉')
} else if (refreshState === RefreshStatus.Refreshing) {
LoadingProgress() // 内置加载动画
Text('刷新中...')
} else {
Text('刷新完成')
}
}
.padding(20)
}
}
关键说明:
RefreshStatus枚举提供Inactive(未触发)、Drag(拖动中)、Refreshing(刷新中)、Success(成功)四种状态。percent参数表示当前下拉距离与触发距离的比值(≥1.0时触发刷新)。- 箭头旋转通过
rotate属性根据percent值控制,达到阈值时翻转180度。 - 刷新动画可使用内置
LoadingProgress组件或自定义Lottie动画。
注意事项:
- 列表滚动到顶部时继续下拉才会触发。
- 刷新完成后需手动将
isRefreshing设为false以结束动画。 - 可结合
refreshState和percent实现更精细的动画效果。
此方案直接使用ArkUI原生组件,无需第三方库即可实现标准的下拉刷新交互。

