HarmonyOS APP开发---"新鲜事"社交动态App,需要用到这个库
做一个社交动态 App,信息流要下拉刷新最新动态、上拉加载历史内容。ArkUI 原生 List 不带这套交互------
@ohos/pulltorefresh一个组件包住 List,下拉上拉全搞定,还支持自定义动画。
📦 仓库地址:gitcode.com/CPF-Applica... | 安装:ohpm install @ohos/pulltorefresh
写在前面
"新鲜事"是一个社交动态 App,核心页面就是信息流:用户下拉刷新看最新动态,滑到底部上拉加载更早的内容。这个交互在微信朋友圈、微博、抖音里都是标配。
但 ArkUI 原生的 List / Scroll / Grid / WaterFlow 组件本身不带下拉刷新和上拉加载能力。如果你自己监听手势 + 写动画 + 处理数据加载,每个列表都要重复写一遍。
@ohos/pulltorefresh 用一个组件把你的列表"包"起来:
- 下拉刷新 :
onRefresh回调返回 Promise,resolve 后动画收起 - 上拉加载 :
onLoadMore回调返回 Promise,resolve 后加载状态消失 - 5 大容器支持:List / Scroll / Tabs / Grid / WaterFlow
- 自定义动画:内置精美动画,也可以完全自定义刷新/加载视图
- LazyForEach 兼容:长列表懒加载性能不打折
这篇文章聊什么
- 基础信息流------PullToRefresh + List + 下拉/上拉
- 自定义动画------替换内置刷新动画
- V2 组件------@ComponentV2 新写法
flowchart TD
A[信息流页面] --> B[PullToRefresh 包住 List]
B --> C{用户手势}
C -->|下拉| D[onRefresh 回调]
D --> E[请求最新动态]
E --> F[resolve 收起动画]
F --> G[更新列表数据]
C -->|滑到底部| H[onLoadMore 回调]
H --> I[请求历史动态]
I --> J[resolve 收起加载]
J --> K[追加到列表尾部]
第一步:安装
bash
ohpm install @ohos/pulltorefresh
第二步:信息流下拉刷新 + 上拉加载
typescript
import { PullToRefresh } from '@ohos/pulltorefresh'
@Entry
@Component
struct FeedPage {
private scroller: Scroller = new Scroller()
@State feedList: string[] = ['动态1', '动态2', '动态3']
private page: number = 1
build() {
PullToRefresh({
// 必传:列表数据
data: $feedList,
// 必传:列表容器
scroller: this.scroller,
// 必传:自定义主体布局
customList: () => { this.getListView() },
// 下拉刷新
onRefresh: () => {
return new Promise<string>((resolve) => {
// 请求最新动态
fetchLatestFeed().then((data) => {
this.feedList = data // 替换列表
this.page = 1
resolve('刷新成功') // 收起刷新动画
})
})
},
// 上拉加载更多
onLoadMore: () => {
return new Promise<string>((resolve) => {
this.page++
fetchMoreFeed(this.page).then((data) => {
this.feedList = this.feedList.concat(data) // 追加到尾部
resolve('')
})
})
},
})
}
@Builder
getListView() {
List({ scroller: this.scroller }) {
ForEach(this.feedList, (item: string) => {
ListItem() {
// 每条动态的 UI
Column({ space: 8 }) {
Text(item).fontSize(16)
Text('来自新鲜事').fontSize(12).fontColor('#999')
}
.width('100%').padding(16)
}
}, (item: string) => item)
}
.edgeEffect(EdgeEffect.None) // ⚠️ 必须设置!
}
}
关键点:
onRefresh/onLoadMore都返回 Promise------组件内部根据 resolve 自动收/放动画- 容器的
edgeEffect必须设为EdgeEffect.None(否则弹簧效果冲突) data绑定让组件感知列表数据变化
第三步:自定义刷新动画
内置动画够用,但你也可以完全自定义:
typescript
PullToRefresh({
data: $feedList,
scroller: this.scroller,
customList: () => { this.getListView() },
onRefresh: () => { /* ... */ },
onLoadMore: () => { /* ... */ },
// 自定义下拉刷新视图(替换内置动画)
customRefresh: () => {
this.CustomRefreshView()
},
// 自定义上拉加载视图
customLoad: () => {
this.CustomLoadView()
},
})
@Builder
CustomRefreshView() {
Row({ space: 8 }) {
LoadingProgress().width(24).height(24)
Text('正在刷新新鲜事...').fontSize(14).fontColor('#4ECDC4')
}
.height(60)
.justifyContent(FlexAlign.Center)
}
第四步:V2 组件写法(@ComponentV2)
鸿蒙新推荐 @ComponentV2 写法,PullToRefresh 也支持:
typescript
import { PullToRefreshV2 } from '@ohos/pulltorefresh'
@Entry
@ComponentV2
struct FeedPageV2 {
private scroller: Scroller = new Scroller()
@Local feedList: string[] = []
build() {
PullToRefreshV2({
data: this.feedList,
scroller: this.scroller,
customList: () => { this.listView() },
onRefresh: () => { /* ... */ },
onLoadMore: () => { /* ... */ },
})
}
@Builder
listView() {
List({ scroller: this.scroller }) {
ForEach(this.feedList, (item: string) => {
ListItem() { Text(item).height(80) }
}, (item: string) => item)
}
.edgeEffect(EdgeEffect.None)
}
}
为什么"新鲜事"选了 pulltorefresh?
| 需求 | 自己手写 | @ohos/pulltorefresh |
|---|---|---|
| 下拉刷新 | 手势监听+动画 | ✅ onRefresh 一行 |
| 上拉加载 | 滚动监听+判断 | ✅ onLoadMore 一行 |
| List/Grid/WaterFlow | 每个容器各写 | ✅ 5 大容器通用 |
| 自定义动画 | 手写 | ✅ customRefresh |
| LazyForEach | 需适配 | ✅ 完美兼容 |
| V2 组件 | --- | ✅ PullToRefreshV2 |
总结
"新鲜事"这个场景里,@ohos/pulltorefresh 解决了三件事:
- 下拉刷新 ------
onRefresh返回 Promise,请求完成自动收起动画 - 上拉加载 ------
onLoadMore返回 Promise,加载完成自动收起状态 - 5 大容器通用------List / Scroll / Tabs / Grid / WaterFlow 一个组件全包
如果你也在做信息流、商品列表、聊天记录等任何"滚动 + 分页"的场景,@ohos/pulltorefresh 让你 5 分钟搞定刷新加载,把精力留给内容本身。