鸿蒙App开发-网络请求-下拉刷新三方库-底部Tab栏-滚动组件(含源码)

本文介绍一个基于鸿蒙ArkTS开发的App,是一个包含轮播图、文章列表和 Web 页面等功能的多页面应用。

本文主要内容包括:

一、效果图

首页
详情页

  

二、内容简介

1.底部Tab栏和两个页面

        App底部是一个TabBar,点击TabBar可以切换上面的页面。共包含两个页面,一个是“首页” ,另一个是“空白页”。

2.顶部Banner

        App顶部是一个Banner,也叫轮播图,点击轮播图可以跳转到对应的详情页面。

3.List组件

        轮播图下方是一个List组件,点击其中某一项可以跳转详情页面。

4.WebView

使用系统组件@ohos.web.webview 显示网页。同时,此详情页面顶部有一个标题栏,用于显示返回键和标题。

三、实现说明

1.主界面

首先实现主界面,包含一个TabBar和上面的两个页面,以下是主界面代码:

import Constants from '../Constants/Constants'
import Home from './Home';
import EmptyPage from './EmptyPage';
@Entry
@Component
struct Index {
  @State currentTabIndex: number = 0;
  tabsController: TabsController;
  aboutToAppear(){
    this.tabsController = new TabsController();
  }
  @Builder TabBuilder(title: string, index: number, icon: Resource) {
    Column() {
      Image(icon)
        .width($r('app.float.mainPage_baseTab_size'))
        .height($r('app.float.mainPage_baseTab_size'))
        .fillColor(this.getTabBarColor(index))
      Text(title)
        .margin({ top: $r('app.float.mainPage_baseTab_top') })
        .fontSize($r('app.float.main_tab_fontSize'))
        .fontColor(this.getTabBarColor(index))
    }
    .justifyContent(FlexAlign.Center)
    .height($r('app.float.mainPage_barHeight'))
    .width(Constants.FULL_PARENT)
    .onClick(() => {
      this.currentTabIndex = index;
      this.tabsController.changeIndex(this.currentTabIndex)
    })
  }

  // 获取选项卡栏颜色
  getTabBarColor(index: number){
    if(index == this.currentTabIndex){
      return Color.Blue;
    }else{
      return Color.Gray;
    }
  }

  build() {
    Tabs({
      barPosition: BarPosition.End,
      controller: this.tabsController
    }) {
      // 首页
      TabContent() {
        Home()
      }
      .padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
      .backgroundColor($r('app.color.mainPage_backgroundColor'))
      .tabBar(this.TabBuilder(Constants.HOME_TITLE, Constants.HOME_TAB_INDEX
        , $r('app.media.ic_bottom_home')))

      // 项目
      TabContent() {
        EmptyPage()
      }
      .padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
      .backgroundColor($r('app.color.mainPage_backgroundColor'))
      .tabBar(this.TabBuilder(Constants.EMPTY_TITLE, Constants.EMPTY_TAB_INDEX
        , $r('app.media.ic_bottom_empty')))
    }
    .width(Constants.FULL_PARENT)
    .backgroundColor(Color.White)
    .barHeight($r('app.float.mainPage_barHeight'))
    .barMode(BarMode.Fixed)
    .onChange((index: number) => {
      this.currentTabIndex = index;
    })
  }
}
2.首页

本文主要实现的就是首页,用竖向列包含了Banner组件和ArticleList组件,代码如下:

@Component
export default struct Home {
  build() {
    Column() {
      Banner();
      ArticleList();
    }
  }
}

其中Banner组件代码如下,代码中有具体实现的解释:

// 标记为组件
@Component
  // 导出名为 Banner 的结构体
export default struct Banner {
  // Swiper 控制器
  swiperController: SwiperController = new SwiperController();
  // 轮播图数据
  @State bannerData: HomeBannerItemBean[] = [];

  // 生命周期钩子,在即将显示时调用
  aboutToAppear() {
    // 获取轮播图数据
    this.getData();
  }

  // 异步获取轮播图数据
  async getData(){
    await HomeViewModel.getHomeBanner(Constants.GET_HOME_BANNER).then((data: HomeBannerItemBean[]) => {
      // 将获取到的数据赋值给轮播图数据
      this.bannerData = data;
    }).catch((err: string | Resource) => {
      // 如果发生错误,显示提示消息
      promptAction.showToast({
        message: err,
        duration: Constants.ANIMATION_DURATION
      });
    });
  }

  // 构建界面
  build() {
    // 垂直排列的列
    Column() {
      // 如果有轮播图数据且数据长度大于 0
      if(this.bannerData && this.bannerData.length > 0){
        // 使用 Swiper 组件创建轮播图
        Swiper(this.swiperController) {
          // 遍历轮播图数据
          ForEach(this.bannerData, (banner: HomeBannerItemBean) => {
            // 显示图片,并设置圆角和点击事件
            Image(banner.imagePath).borderRadius($r('app.float.home_swiper_borderRadius')).onClick(() => {
              // 点击事件:跳转到 Web 页面,并传递标题和链接参数
              router.pushUrl({
                url: 'pages/WebPage',
                params: {
                  title: banner.title,
                  src: banner.url
                }
              }, router.RouterMode.Single)
            })
          }, (img: Resource) => JSON.stringify(img.id))
        }
        // 设置轮播图的外边距、自动播放、宽度和高度
        .margin({top: $r('app.float.home_swiper_margin')})
        .autoPlay(true)
        .width(Constants.FULL_PARENT)
        .height(200)
      }
    }
  }
}

那么在Banner组件下方的ArticleList组件,代码如下:

// 标记为组件
@Component
// 导出名为 ArticleList 的结构体
export default struct ArticleList {
  // 是否还有更多数据
  hasMore: boolean = true;
  // 当前页码
  currentPage: number = 0;
  // 每页数据量
  pageSize: number = 30;
  // 文章数据数组
  @State articleData: ArticleItemData[] = [];
  // 需绑定列表或宫格组件的滚动控制器
  private scroller: Scroller = new Scroller();

  // 生命周期钩子,在即将显示时调用
  aboutToAppear() {
    // 获取文章列表数据,参数为 true 表示重置数据
    this.getArticleList(true);
  }

  // @Builder 修饰的私有方法,用于创建列表视图
  @Builder
  private getListView() {
    // 使用 List 组件创建列表
    List({ space: 10, scroller: this.scroller }) {
      // 遍历文章数据
      ForEach(this.articleData, (item: ArticleItemData) => {
        // 使用 ListItem 创建列表项
        ListItem() {
          // 使用 Flex 创建布局
          Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, }) {
            // 作者和发布时间
            Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, }) {
              Text(item.author)
                .fontSize(13)
              Text(Util.dateTime(item.publishTime))
                .fontSize(13)
            }.margin({ top: 10, left: 30, right: 30 })

            // 文章标题
            Text(item.title)
              .width('100%')
              .fontSize(20)
              .textAlign(TextAlign.Center)
              .fontWeight(FontWeight.Bold)
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
              .margin({ left: 10, right: 10 })

            // 文章分类
            Text(item.chapterName)
              .fontSize(13)
              .textAlign(TextAlign.Start)
              .width('100%')
              .margin({ left: 30, bottom: 10 })
          }.borderRadius($r('app.float.home_list_borderRadius'))
          .backgroundColor(Color.White)
        }.onClick(() => {
          // 点击列表项跳转到 Web 页面,传递标题和链接参数
          router.pushUrl({
            url: 'pages/WebPage',
            params: {
              title: item.title,
              src: item.link
            }
          }, router.RouterMode.Single)
        })
      })
    }
    // 设置列表的圆角
    .borderRadius($r('app.float.home_list_borderRadius'))
    // .divider({ strokeWidth: 1, color: 0x222222 })
    // 设置列表的边缘效果为无效果
    .edgeEffect(EdgeEffect.None)
    // 设置列表宽度和高度为100%
    .width('100%')
    .height('100%')
  }

  // 异步获取文章列表数据
  async getArticleList(reset: boolean) {
    await HomeViewModel.getHomeArticleList(this.currentPage, this.pageSize, Constants.GET_HOME_ARTICLE_LIST)
      .then((data: ArticleDataBean) => {
        // 判断是否还有更多数据
        if (data.curPage < data.pageCount) {
          this.currentPage++;
          this.hasMore = true;
        } else {
          this.hasMore = false;
        }
        // 根据参数判断是否重置数据
        if (reset) {
          this.articleData = data.datas;
        } else {
          this.articleData = this.articleData.concat(data.datas);
        }
      }).catch((err: string | Resource) => {
        // 显示错误提示
        promptAction.showToast({ message: err });
      })
  }

  // 构建界面
  build() {
    // 使用 Column 组件创建垂直布局
    Column() {
      // 使用 PullToRefresh 组件实现下拉刷新和上拉加载
      PullToRefresh({
        customRefresh: null,
        customLoad: null,
        data: $articleData, // 数据源数组
        scroller: this.scroller, // 控制器,负责关闭下拉和上拉
        customList: () => {
          // 调用 getListView 方法创建列表视图
          this.getListView();
        },
        onRefresh: () => {
          return new Promise<string>((resolve, reject) => {
            // 下拉刷新成功后解析数据,重新获取文章列表数据
            resolve('下拉刷新成功')
            this.getArticleList(true);
          });
        },
        onLoadMore: () => {
          // 上拉加载成功后解析数据,继续获取更多文章列表数据
          return new Promise<string>((resolve, reject) => {
            resolve('上拉加载成功')
            this.getArticleList(false);
          });
        }
      })
    }.backgroundColor("#efefef") // 设置背景颜色
  }
}

这个文章列表组件,使用了 PullToRefresh 组件和 List 组件展示通过网络获取的文章列表数据,并且点击其中每一项都可以跳转详情页面,使用到的系统方法是router.pushUrl。

3.网络请求

其中网络请求代码如下:

/**
 * 发起 HTTP GET 请求的函数
 * @param url 请求的 URL 地址
 * @param extraData 额外的请求数据,可选参数
 * @returns 返回 Promise 对象,包含 ResponseResult 数据
 */
export function httpRequestGet(url: string, extraData?: Record<string, any>): Promise<ResponseResult> {
  // 创建 HTTP 请求实例
  let httpRequest = http.createHttp();
  
  // 发起 HTTP GET 请求
  let responseResult = httpRequest.request(url, {
    method: http.RequestMethod.GET,
    readTimeout: Constants.HTTP_READ_TIMEOUT,
    header: {
      'Content-Type': ContentType.JSON
    },
    connectTimeout: Constants.HTTP_READ_TIMEOUT,
    extraData: extraData || {}  // 使用 extraData 参数,如果不存在则传递一个空对象
  });

  // 创建用于存储响应数据的对象
  let serverData: ResponseResult = new ResponseResult();

  // 处理返回的数据并返回结果
  return responseResult.then((value: http.HttpResponse) => {
    // 检查 HTTP 响应码是否为成功状态(200)
    if (value.responseCode === Constants.HTTP_CODE_200) {
      // 解析返回的数据
      let result = `${value.result}`;
      let resultJson: ResponseResult = JSON.parse(result);
      
      // 检查服务器返回的错误码是否为成功状态
      if (resultJson.errorCode === Constants.SERVER_CODE_SUCCESS) {
        // 将返回的数据赋值给 serverData 对象
        serverData.data = resultJson.data;
      }
      // 将服务器返回的错误码和错误消息赋值给 serverData 对象
      serverData.errorCode = resultJson.errorCode;
      serverData.errorMsg = resultJson.errorMsg;
    } else {
      // 设置错误消息,包含 HTTP 错误码
      serverData.errorMsg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
    }
    // 返回处理后的 serverData 对象
    return serverData;
  }).catch((err) => {
    // 捕获异常,打印错误信息,并设置错误消息
    console.log("error:" + JSON.stringify(err));
    serverData.errorMsg = $r('app.string.http_error_message');
    // 返回处理后的 serverData 对象
    return serverData;
  });
}
4.详情页面

详情页面是通过webview来展示网页实现的,代码如下:

// 标记为入口
@Entry
// 标记为组件
@Component
// Web 页面结构体
struct WebPage {
  // 从路由获取参数中的 'src',并存储到状态中
  @State src: string = router.getParams()?.['src'];
  // 从路由获取参数中的 'title',并存储到状态中
  @State title: string = router.getParams()?.['title'];

  // Web 页面控制器
  controller: web_webview.WebviewController = new web_webview.WebviewController();

  // 构建界面
  build() {
    // 使用 Column 组件创建垂直布局
    Column() {
      // 页面标题组件
      PageTitle({ titleName: this.title })

      // 分隔线
      Divider()
        .strokeWidth('1px')
        .color($r('sys.color.ohos_id_color_list_separator'))

      // Web 组件,加载指定的网址,并使用控制器进行交互
      Web({
        src: this.src, controller: this.controller
      }).javaScriptAccess(true)
    }
  }
}

// 页面标题组件结构体
@Component
struct PageTitle {
  // 标题名称
  private titleName: string

  // 构建界面
  build() {
    // 使用 Row 组件创建水平布局
    Row() {
      // 返回按钮图标
      Image($r('app.media.back'))
        .width(20)
        .height(20)
        .onClick(() => {
          // 点击返回按钮,触发路由返回操作
          router.back()
        })

      // 标题文本
      Text(this.titleName)
        .fontSize(Constants.PAGE_TITLE_TEXT_SIZE)
        .width(Constants.PAGE_TITLE_TEXT_WIDTH)
        .maxLines(Constants.PAGE_TITLE_TEXT_MAX_LINES)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
        .margin({ left: 20 })
    }
    // 设置整体内边距
    .padding(12)
    // 设置整体宽度为100%
    .width('100%')
  }
}

四、源码地址

WanAndroid: 基于鸿蒙ArkTS语言实现的WanAndroid App

如果觉得本文不错的话,帮忙点个赞吧~感谢~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/321645.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java多线程(并发)夯实之路-CAS原理与应用深入浅出

CAS&#xff1a;保护共享资源的无锁实现 CAS CompareAndSet&#xff0c;简称CAS&#xff08;也有Compare And Swap的说法&#xff09;&#xff0c;它是原子的 它会将pre即之前的值和最新值进行比较&#xff0c;如果相同&#xff0c;修改为next&#xff0c;不同则修改失败 …

Python超详细基础文件操作(详解版)

一、文件操作 1. 文件打开与关闭 1.1 打开文件 在Python中&#xff0c;你可以使用 open() 函数来打开文件。 以下是一个简单的例子&#xff1a; # 打开文件&#xff08;默认为只读模式&#xff09; file_path example.txt with open(file_path, r) as file:# 执行文件操作…

M-VAE

Word2Vec c(y) 辅助信息 作者未提供代码

golang 反序列化出现json: cannot unmarshal string into Go value of type model.Phone

项目场景&#xff1a; 今天在项目公关的过程中&#xff0c;需要对interface{}类型进行转换为具体结构体 问题描述 很自然的用到了resultBytes, _ : json.Marshal(result)&#xff0c;然后对resultBytes进行反序列化转换为对应的结构体err : json.Unmarshal(resultBytes, &…

通俗易懂实现功能强大的实战项目 springboot+java+vue+mysql 膳食营养健康网站

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

idea2020.1 x64实现git的push

今天还有点时间&#xff0c;顺便写一下这个。 我这边只说一下远程仓库&#xff08;gitee&#xff09;的push 点击之后会弹出 点击&#xff0c;弹出 输入你定义的远程仓库名&#xff08;自己起&#xff09;&#xff0c;以及url&#xff0c;url由下面获取 在你的gitee创建好仓库…

【NI国产替代】PXIe‑6375,208路AI(16位,3.8 MS/s),2路AO,24路DIO,PXI多功能I/O模块

PXIe&#xff0c;208路AI&#xff08;16位&#xff0c;3.8 MS/s&#xff09;&#xff0c;2路AO&#xff0c;24路DIO&#xff0c;PXI多功能I/O模块 PXIe‑6375提供了模拟I/O、数字I/O和四个32位计数器/定时器&#xff0c;用于PWM、编码器、频率、事件计数等应用。 该设备利用高吞…

OAuth 2.0 - 微信登录

一、概述 1、什么是OAuth 2.0 OAuth (Open Authorization) 是一个关于授权 (athorization) 的开放网络标准。 允许用户授权第三应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方。OAuth在全世界得到广泛应用&#xff0c;目前的版本…

实例分割论文精读:Mask R-CNN

1.摘要 本文提出了一种概念简单、灵活、通用的实例分割方法&#xff0c;该方法在有效地检测图像中的物体同时&#xff0c;为每个物体实例生成一个实例分割模板&#xff0c;添加了一个分支&#xff0c;用于预测一个对象遮罩&#xff0c;与现有的分支并行&#xff0c;用于边界框…

【Unity】【VRTK】【Pico】如何快速在VRTK中引入带动画的PICO控制器

【背景】 之前的VRTK篇章中,我只介绍了Oculus,Open VR,SImulator这三种Rig的配置方法,那么Pico如何融合VRTK进行开发呢? 【需要的开发包】 先像一个正常PICO项目那样导入PICO的SDK到Unity。VRTK 4的Package导入器中搜Pico,可以导入一个Pico的Integration,导入后Projec…

陀螺仪LSM6DSV16X与AI集成(6)----检测自由落体

陀螺仪LSM6DSV16X与AI集成.6--检测自由落体 概述视频教学样品申请源码下载生成STM32CUBEMX串口配置IIC配置CS和SA0设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置 概述 本文介绍如何初始化传感器并配置其参数&#xff0c;以便在检测到自由落体事件时发送通知。 最近…

回归预测 | Python基于ISSA多策略改进麻雀优化ISSA-CNN-BiLSTM多输入单输出回归预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 原创改进&#xff0c; ISSA多策略改进麻雀优化ISSA-CNN-BiLSTM 多输入单输出回归 python代码 优化参数&#xff1a;filter,unints1,units2&#xff0c;学习率&#xff08;可添加&#xff09; 以下是三个主要的改进点&…

Echarts折线图中数据根据正负数显示不同区域背景色-配置

示例 Echarts折线图中数据根据正负数显示不同区域背景色 Piecewise 分段类型Continuous 连续类型 Echarts配置 option {backgroundColor: "#030A41",xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun],axisTick: {show: false,},axisLabel: { /…

【Git】本地仓库管理远程库(GitHub)——clone(下载)、commit(添加到本地仓库)、push(提交到远程仓库)、pull(拉取)操作

目录 使用远程仓库的目的将本地仓库同步到git远程仓库 1.克隆远程仓库(clone)2.新建一个文件3.将工作区的文件添加到暂存区4.将暂存区的文件添加到本地仓库(commit)5.提交(同步)到远程仓库(push)6.远程库拉取到本地库(pull)7.团队协作开发和跨团队协作开发(开源项目) 使用远程…

翻译: Streamlit从入门到精通 显示图表Graphs 地图Map 主题Themes 二

Streamlit从入门到精通 系列&#xff1a; 翻译: Streamlit从入门到精通 基础控件 一 1. 使用Streamlit显示图表Graphs 1.1 为什么我们需要可视化&#xff1f; 数据可视化通过将数据整理成更容易理解的格式来讲述故事&#xff0c;凸显趋势和异常点。好的可视化能够讲述一个故…

CAN总线报文格式---远程帧(遥控帧)

远程帧&#xff08;Remote frame&#xff09; 用于向远程节点请求数据。远程帧可分为标准远程帧和扩展远程帧。&#xff08;远程帧又称为遥控帧&#xff09; 通常ECU&#xff08;Electronic Control Unit&#xff09;会通过数据帧主动发送相关数据&#xff0c;但某些情况也可能…

redis数据结构源码分析——跳表zset

文章目录 跳表的基本思想特点节点与结构跳跃表节点zskiplistNode属性 跳跃表链表属性 跳表的设计思想和优势API解析zslCreate&#xff08;创建跳跃表&#xff09;zslCreateNode&#xff08;创建节点&#xff09;zslGetRank&#xff08;查找排位&#xff09;zslDelete&#xff0…

jenkins-cl参数化构建

pipeline片段&#xff08;对应jenkins-cli -p参数的BRANCHdevelop&#xff09; parameters {string(name: BRANCH, defaultValue: master, description: Enter the branch name)}stages {stage(Get Code) {steps {script {def branch params.BRANCHcheckout scmGit(branches: …

关于AMC8模拟考试延长到1月19日14点,以及常见的几个新问题

相信过去的周末两天&#xff0c;很多参加今年AMC8美国数学思维竞赛活动的孩子们都参加了AMC8模拟考试。昨天有家长问六分成长&#xff0c;周末两天因故没能参加要不要紧&#xff1f;如果还想参加怎么办&#xff1f; 不用担心&#xff01;官方已经把AMC8模拟考试的时间延长到1月…

c#异形窗体遮罩效果

c#异形窗体遮罩效果&#xff0c;移动&#xff0c;关闭&#xff0c;最大化&#xff0c;最小化&#xff0c;还原操作 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D…