README.md
1# 下拉刷新与上滑加载案例
2
3### 介绍
4
5本示例介绍使用第三方库的PullToRefresh组件实现列表的下拉刷新数据和上滑加载后续数据。
6
7### 效果图预览
8
9<img src="./pulltorefresh/src/main/resources/base/media/pull_to_refresh_news.gif" width="300">
10
11**使用说明**
12
131. 进入页面,下拉列表触发刷新数据事件,等待数据刷新完成。
142. 上滑列表到底部,触发加载更多数据事件,等待数据加载完成。
15
16### 实现思路
17
181. 使用第三方库pullToRefresh组件,将列表组件、绑定的数据对象和scroller对象包含进去,并添加上滑与下拉方法。源码参考[PullToRefreshNews.ets](./pulltorefresh/src/main/ets/pages/PullToRefreshNews.ets)
19 ```typescript
20 PullToRefresh({
21 // 必传项,列表组件所绑定的数据
22 data: $newsData,
23 // 必传项,需绑定传入主体布局内的列表或宫格组件
24 scroller: this.scroller,
25 // 必传项,自定义主体布局,内部有列表或宫格组件
26 customList: () => {
27 // 一个用@Builder修饰过的UI方法
28 this.getListView();
29 },
30 // 下拉刷新回调
31 onRefresh: () => {
32 return new Promise<string>((resolve, reject) => {
33 ...
34 });
35 },
36 // 上滑加载回调
37 onLoadMore: () => {
38 return new Promise<string>((resolve, reject) => {
39 ...
40 });
41 },
42 customLoad: () => this.customLoad(),
43 customRefresh: null,
44 })
45 ```
462. 使用LazyForEach循环渲染列表。源码参考[PullToRefreshNews.ets](./pulltorefresh/src/main/ets/pages/PullToRefreshNews.ets)
47 ```typescript
48 LazyForEach(this.newsData, (item: NewsData) => {
49 ListItem() {
50 ...
51 }
52 });
53 ```
543. 模拟列表总页数,加载完全部信息后提示已经到底部。源码参考[PullToRefreshNews.ets](./pulltorefresh/src/main/ets/pages/PullToRefreshNews.ets)
55 ```javascript
56 onLoadMore: () => {
57 return new Promise<string>((resolve, reject) => {
58 // 模拟数据列表页超过4页后已到达底部,无法继续加载
59 if (this.newsDataListIndex < NEWS_MAX_LIST) {
60 // 模拟网络请求操作,请求网络1.5秒后得到数据,通知组件变更列表数据
61 setTimeout(() => {
62 let newsModelMockData: Array<NewsData> = getNews(MOCK_DATA_FILE_ONE_DIR)
63 for (let j = 0; j < NEWS_MOCK_DATA_COUNT; j++) {
64 this.newsData.pushData(newsModelMockData[j]);
65 }
66 this.newsDataListIndex++;
67 resolve('');
68 }, NEWS_REFRESH_TIME);
69 } else {
70 // 如果已满4页,更改上拉提示信息提示已经加载完所有数据
71 setTimeout(() => {
72 resolve('');
73 }, NEWS_REFRESH_TIME);
74 }
75 });
76 }
77 ```
784. 自定义上拉加载动画。源码参考[PullToRefreshNews.ets](./pulltorefresh/src/main/ets/pages/PullToRefreshNews.ets)
79 ```typescript
80 @Builder
81 private customLoad() {
82 Row() {
83 Stack() {
84 // 上拉1阶段箭头图片
85 Image(pull_icon_up)
86 .width('100%')
87 .height('100%')
88 .objectFit(ImageFit.Contain)
89 .visibility(this.isPullUp ? Visibility.Visible : Visibility.Hidden)
90 .rotate({
91 z: 1,
92 angle: this.angle1 !== undefined ? this.angle1 : 0
93 })
94 // 加载时图片
95 Image(pull_icon_load)
96 .width('100%')
97 .height('100%')
98 .objectFit(ImageFit.Contain)
99 .visibility(this.isLoading ? Visibility.Visible : Visibility.Hidden)
100 .rotate({
101 z: 1,
102 angle: this.angle2 !== undefined ? this.angle2 : 0
103 })
104 }
105 // 最后一页加载时隐藏加载图片
106 .width(this.newsDataListIndex === NEWS_MAX_LIST && this.isLoading ? 0 :
107 this.refreshConfigurator.getLoadImgHeight())
108 .height(this.newsDataListIndex === NEWS_MAX_LIST && this.isLoading ? 0 :
109 this.refreshConfigurator.getLoadImgHeight())
110
111 // 上拉过程与加载时提示文本
112 Text(this.loadText)
113 .height('100%')
114 .textAlign(TextAlign.Center)
115 .margin({ left: this.newsDataListIndex === NEWS_MAX_LIST && this.isLoading ? 0 : 8 })
116 .fontColor(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadTextColor() : 0)
117 .fontSize(this.refreshConfigurator !== undefined ? this.refreshConfigurator.getLoadTextSize() : 0)
118 }
119 .height('100%')
120 }
121 ```
1225. 设置上拉与加载时的动画回调。源码参考[PullToRefreshNews.ets](./pulltorefresh/src/main/ets/pages/PullToRefreshNews.ets)
123 ```typescript
124 onAnimPullUp: (value, width, height) => {
125 if (value !== undefined && width !== undefined && height !== undefined) {
126 if (value) {
127 this.isLoading = false;
128 this.isPullUp = true;
129 // 判断上拉拖拽过程中高度是否超过阶段临界值
130 if (value < LOAD_PULL_STATE_CHANGE) {
131 // 归零角度,保持箭头朝上
132 this.angle1 = 0;
133 // 改变提示文本为上拉1阶段
134 this.loadText = LOAD_TEXT_PULL_UP_1;
135 } else {
136 // 翻转角度,保持箭头朝下
137 this.angle1 = 180;
138 // 改变提示文本为上拉2阶段
139 this.loadText = LOAD_TEXT_PULL_UP_2;
140 }
141 }
142 }
143 },
144
145 onAnimLoading: (value, width, height) => {
146 if (value !== undefined && width !== undefined && height !== undefined) {
147 if (value) {
148 this.isPullUp = false;
149 this.isLoading = true;
150 // 更改角度使加载图片保持旋转
151 this.angle2 = value * 360;
152 // 判读页码是否为最后一页
153 if (this.newsDataListIndex !== NEWS_MAX_LIST) {
154 this.loadText = LOAD_DEFAULT_TEXT;
155 } else {
156 // 最后一页更换文本提示已经到底了
157 this.loadText = LOAD_STOP_TEXT;
158 }
159 }
160 }
161 }
162 ```
163### 高性能知识点
164
165不涉及
166
167### 工程结构&模块类型
168 ```
169 pulltorefreshnews // har类型
170 |---model
171 |---|---AppInfo.ets // App信息
172 |---|---UserInformation.ets // 用户信息
173 |---view
174 |---|---PullToRefreshNews.ets // 视图层-场景列表页面
175 ```
176
177### 模块依赖
178
179[PullToRefresh](https://gitee.com/openharmony-sig/PullToRefresh)
180
181### 参考资料
182
183[PullToRefresh](https://gitee.com/openharmony-sig/PullToRefresh)
184[LazyForEach](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-rendering-control-lazyforeach.md)
185[PullToRefresh第三方库](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fpulltorefresh)
186
187### 相关权限
188
189不涉及。
190
191### 依赖
192
193不涉及。
194
195### 约束与限制
196
1971.本示例仅支持标准系统上运行,支持设备:RK3586。
198
1992.本示例为Stage模型,支持API12版本SDK,SDK版本号(API Version 12 Release)。
200
2013.本示例需要使用DevEco Studio版本号(DevEco Studio 5.0.0 Release)及以上版本才可编译运行。
202
203### 下载
204
205如需单独下载本工程,执行如下命令:
206
207```shell
208git init
209git config core.sparsecheckout true
210echo code/UI/PullToRefresh/ > .git/info/sparse-checkout
211git remote add origin https://gitee.com/openharmony/applications_app_samples.git
212git pull origin master