赞
踩
介绍
本篇Codelab是基于ArkTS的声明式开发范式实现的样例,主要介绍了数据请求和touch事件的使用。包含以下功能:
网络数据请求需要申请权限:ohos.permission.INTERNET。
本篇Codelab需要搭建服务端环境,服务端如何搭建将在代码工程目录的README中详细介绍,文档中不再赘述。
源码下载
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
代码结构解读
本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。
- ├──entry/src/main/ets // ArkTS代码区
- │ ├──common
- │ │ ├──constant
- │ │ │ └──CommonConstant.ets // 公共常量类
- │ │ └──utils
- │ │ ├──HttpUtil.ets // 网络请求方法
- │ │ ├──Logger.ets // 日志工具类
- │ │ ├──PullDownRefresh.ets // 下拉刷新方法
- │ │ └──PullUpLoadMore.ets // 上拉加载更多方法
- │ ├──entryability
- │ │ └──EntryAbility.ts // 程序入口类
- │ ├──pages
- │ │ └──Index.ets // 主页面
- │ ├──view
- │ │ ├──CustomRefreshLoadLayout.ets // 下拉刷新、上拉加载布局文件
- │ │ ├──LoadMoreLayout.ets // 上拉加载布局封装
- │ │ ├──NewsItem.ets // 新闻数据
- │ │ ├──NewsList.ets // 新闻列表
- │ │ ├──NoMoreLayout.ets // 上拉停止布局封装
- │ │ ├──RefreshLayout.ets // 下拉刷新布局封装
- │ │ └──TabBar.ets // 新闻类型页签
- │ └──viewmodel
- │ ├──NewsModel.ets // 新闻模型类
- │ └──NewsViewModel.ets // 新闻ViewModel
- ├──entry/src/main/resources // 资源文件目录
- └──HttpServerOfNews // 服务端代码
构建主界面
本章节将介绍新闻列表页面的实现,用tabBar展示新闻分类,tabContent展示新闻列表,效果图如图所示:
在TabBar.ets文件中的aboutToAppear()方法里获取新闻分类。
- // TabBar.ets
- aboutToAppear() {
- // 请求服务端新闻类别
- NewsViewModel.getNewsTypeList().then((typeList: NewsTypeBean[]) => {
- this.tabBarArray = typeList;
- }).catch((typeList: NewsTypeBean[]) => {
- this.tabBarArray = typeList;
- });
- }
在NewsList.ets文件中的aboutToAppear()方法里获取新闻数据,将数据加载到新闻列表页面ListLayout布局中。
- // NewsList.ets
- changeCategory() {
- this.newsModel.currentPage = 1;
- NewsViewModel.getNewsList(this.newsModel.currentPage, this.newsModel.pageSize, Const.GET_NEWS_LIST)
- .then((data: NewsData[]) => {
- this.newsModel.pageState = PageState.Success;
- if (data.length === this.newsModel.pageSize) {
- this.newsModel.currentPage++;
- this.newsModel.hasMore = true;
- } else {
- this.newsModel.hasMore = false;
- }
- this.newsModel.newsData = data;
- })
- .catch((err: string | Resource) => {
- promptAction.showToast({
- message: err,
- duration: Const.ANIMATION_DURATION
- });
- this.newsModel.pageState = PageState.Fail;
- });
- }
- aboutToAppear() {
- // 请求服务端新闻数据
- this.changeCategory();
- }
- ...
- @Builder ListLayout() {
- List() {
- ...
- ForEach(this.newsModel.newsData, (item: NewsData) => {
- ListItem() {
- // 新闻数据
- NewsItem({ newsData: item })
- }
- .height($r('app.float.news_list_height'))
- .backgroundColor($r('app.color.white'))
- .margin({ top: $r('app.float.news_list_margin_top') })
- .borderRadius(Const.NewsListConstant_ITEM_BORDER_RADIUS)
- }, (item: NewsData, index?: number) => JSON.stringify(item) + index)
- ...
- }
- ...
- }
数据请求
在module.json5文件中配置如右侧所示权限:
这一章节,将基于新闻数据请求来介绍如何从服务端请求数据。
- // module.json5
- "requestPermissions": [
- {
- "name": "ohos.permission.INTERNET",
- "reason": "$string:dependency_reason",
- "usedScene": {
- "abilities": [
- "EntryAbility"
- ],
- "when": "inuse"
- }
- }
- ]
导入http模块,封装httpRequestGet方法,调用者传入url地址发起网络数据请求。
- // HttpUtil.ets
- import http from '@ohos.net.http';
- ...
- export function httpRequestGet(url: string): Promise<ResponseResult> {
- let httpRequest = http.createHttp();
- // 发送数据请求
- let responseResult = httpRequest.request(url, {
- method: http.RequestMethod.GET,
- readTimeout: Const.HTTP_READ_TIMEOUT,
- header: {
- 'Content-Type': ContentType.JSON
- },
- connectTimeout: Const.HTTP_READ_TIMEOUT,
- extraData: {}
- });
- let serverData: ResponseResult = new ResponseResult();
- // 处理数据,并返回
- return responseResult.then((value: http.HttpResponse) => {
- Logger.info(`http value ${JSON.stringify(value)}`);
- if (value.responseCode === Const.HTTP_CODE_200) {
- // 获取返回数据
- let result = `${value.result}`;
- let resultJson: ResponseResult = JSON.parse(result);
- if (resultJson.code === Const.SERVER_CODE_SUCCESS) {
- serverData.data = resultJson.data;
- }
- serverData.code = resultJson.code;
- serverData.msg = resultJson.msg;
- } else {
- serverData.msg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
- }
- return serverData;
- }).catch(() => {
- serverData.msg = $r('app.string.http_error_message');
- return serverData;
- })
- }
在NewsViewModel.ets文件中封装getNewsList方法,调用httpRequestGet方法请求服务端,用Promise异步保存返回的新闻数据列表。
- // NewsViewModel.ets
- // 获取服务端新闻数据列表
- getNewsList(currentPage: number, pageSize: number, path: string): Promise<NewsData[]> {
- return new Promise(async (resolve: Function, reject: Function) => {
- let url = `${Const.SERVER}/${path}`;
- url += '?currentPage=' + currentPage + '&pageSize=' + pageSize;
- httpRequestGet(url).then((data: ResponseResult) => {
- if (data.code === Const.SERVER_CODE_SUCCESS) {
- resolve(data.data);
- } else {
- Logger.error('getNewsList failed', JSON.stringify(data));
- reject($r('app.string.page_none_msg'));
- }
- }).catch((err: Error) => {
- Logger.error('getNewsList failed', JSON.stringify(err));
- reject($r('app.string.http_error_message'));
- });
- });
- }
下拉刷新
本章节将以下拉刷新的功能效果来介绍touch事件的使用。效果图如图所示:
创建一个下拉刷新布局CustomLayout,动态传入刷新图片和刷新文字描述。
- // CustomRefreshLoadLayout.ets
- build() {
- Row() {
- // 下拉刷新图片
- Image(this.customRefreshLoadClass.imageSrc)
- ...
- // 下拉刷新文字
- Text(this.customRefreshLoadClass.textValue)
- ...
- }
- ...
- }
将下拉刷新的布局添加到NewsList.ets文件中新闻列表布局ListLayout里面,监听ListLayout组件的onTouch事件实现下拉刷新。
- // NewsList.ets
- build() {
- Column() {
- if (this.newsModel.pageState === PageState.Success) {
- this.ListLayout()
- }
- ...
- }
- ...
- .onTouch((event: TouchEvent | undefined) => {
- if (event) {
- if (this.newsModel.pageState === PageState.Success) {
- listTouchEvent(this.newsModel, event);
- }
- }
- })
- }
- ...
- @Builder ListLayout() {
- List() {
- ListItem() {
- RefreshLayout({
- refreshLayoutClass: new CustomRefreshLoadLayoutClass(this.newsModel.isVisiblePullDown, this.newsModel.pullDownRefreshImage,
- this.newsModel.pullDownRefreshText, this.newsModel.pullDownRefreshHeight)
- })
- ...
- }
- }
- ...
- }
上拉加载也是通过touch事件来实现的,此处不再赘叙,有兴趣的同学可参考代码。
- // PullDownRefresh.ets
- export function listTouchEvent(newsModel: NewsModel, event: TouchEvent) {
- switch (event.type) {
- ...
- case TouchType.Move:
- if ((newsModel.isRefreshing === true) || (newsModel.isLoading === true)) {
- return;
- }
- let isDownPull = event.touches[0].y - newsModel.lastMoveY > 0;
- if (((isDownPull === true) || (newsModel.isPullRefreshOperation === true)) && (newsModel.isCanLoadMore === false))
- {
- // 手指移动,处理下拉刷新
- touchMovePullRefresh(newsModel, event);
- }
- ...
- break;
- }
- }
- export function touchMovePullRefresh(newsModel: NewsModel, event: TouchEvent) {
- if (newsModel.startIndex === 0) {
- newsModel.isPullRefreshOperation = true;
- let height = vp2px(newsModel.pullDownRefreshHeight);
- newsModel.offsetY = event.touches[0].y - newsModel.downY;
- // 滑动偏移量大于下拉刷新布局高度,满足刷新条件。
- if (newsModel.offsetY >= height) {
- pullRefreshState(newsModel, RefreshState.Release);
- newsModel.offsetY = height + newsModel.offsetY * Const.Y_OFF_SET_COEFFICIENT;
- } else {
- pullRefreshState(newsModel, RefreshState.DropDown);
- }
- if (newsModel.offsetY < 0) {
- newsModel.offsetY = 0;
- newsModel.isPullRefreshOperation = false;
- }
- }
- }
- export function pullRefreshState(newsModel: NewsModel, state: number) {
- switch (state) {
- ...
- case RefreshState.Release:
- newsModel.pullDownRefreshText = $r('app.string.release_refresh_text');
- newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh');
- newsModel.isCanRefresh = true;
- newsModel.isRefreshing = false;
- break;
- case RefreshState.Refreshing:
- newsModel.offsetY = vp2px(newsModel.pullDownRefreshHeight);
- newsModel.pullDownRefreshText = $r('app.string.refreshing_text');
- newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load');
- newsModel.isCanRefresh = true;
- newsModel.isRefreshing = true;
- break;
- case RefreshState.Success:
- newsModel.pullDownRefreshText = $r('app.string.refresh_success_text');
- newsModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh');
- newsModel.isCanRefresh = true;
- newsModel.isRefreshing = true;
- break;
- ...
- default:
- break;
- }
- }
总结
您已经完成了本次Codelab的学习,并了解到以下知识点:
使用List组件实现数据列表。
使用Tabs、TabContent组件实现内容视图切换。
网络数据请求。
触摸事件onTouch的使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。