鸿蒙 ArkTS Tabs组件实现类微信(可滑动的)tabBar页签切换页面功能 ...

张裕  论坛元老 | 2024-6-20 20:11:40 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1395|帖子 1395|积分 4185

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
关键词:harmonyOS   鸿蒙开发  ArkTS  TabContent
使用场景:类微信底部导航栏,点击/左右滑动切换页面并加载数据
开发环境:ArkTS3.1  API9  Phone设备
HMOS Dev官方文档:文档中央
演示效果:


目录
完整Demo已提交至Gitee
搭建页面
自界说TabContent(往后翻有完整代码)
思路
开始
完整自界说tabs代码
页面切换后怎样加载新数据
介绍
父子组件表明
开始
页面切换时可加载新数据的完整代码


   完整Demo已提交至Gitee,传送门:
  鸿蒙ArkTS tabBar页签切换Demo: HarmonyOS鸿蒙ArkTS tabBar页签切换完整项目Demo
  

搭建页面

我这里用三个页面举例,新建home、info、mine页面,创建components目录存放自界说Tabs组件,目录结构如下,我这里已经预备了6个图标图片存放在了resources/rawfile/tabs


自界说Tabs(附完整代码)

思路

index为应用加载的首页,加载自界说Tabs组件,Tabs组件中加载各个页面

开始

HMOS Dev官方文档 TabContent :文档中央
1.起首在index.est中导入自界说Tabs组件,避免与官方组件冲突取名comTabs

2.在自界说Tabs组件中导入所建的三个页面[如图3],记得在页面中使用export导出[如图4]

[左图3 | 右图4]
3.设置一个PAGE的枚举,增强可读性,不喜欢用就0123代替,因为页面切换的回调函数返回的数值从0开始,所以给currentIndex默认设置为0即为home页(@State装饰器修饰的属性当状态改变时,UI会发生对应的渲染改变),changePage本身写来用于更新页面数据函数,稍后会用到。别忘了new TabsController()[如图3]
4.官方提供了多种页签样式,我们使用置于底部的,将Tabs中barPosition属性设置为BarPosition.End。Tabs将占用整个页面,所以宽高需设置为100%。
Tabs组件中需要TabContent来加载页面。[如图5]
在tabBar中自界说页签按钮样式,因重复代码太多,我们可以利用@Builder装饰器来自界说构建函数复用代码。[如图6]
留意:自界说页签设置onClick事件用于改变页面索引,Tabs组件需设置onChange事件,否则页面左右滑动页签状态不会改变。

[图5]


[图6]  

完整自界说tabs代码

  1. // tabs.ets
  2. // home页
  3. import Home from '../pages/home/home'
  4. // info页
  5. import Info from '../pages/info/info'
  6. // mine页
  7. import Mine from '../pages/mine/mine'
  8. enum PAGE{
  9.   HOME = 0,
  10.   INFO = 1,
  11.   MINE = 2
  12. }
  13. @Preview
  14. @Component
  15. export default  struct compTabs{
  16.   @State currentIndex: number = 0;
  17.   private tabsController: TabsController = new TabsController();
  18.   changePage(e){
  19.     this.currentIndex = e
  20.     if (e == PAGE.HOME){
  21.     }
  22.     if (e == PAGE.INFO){
  23.     }
  24.     if (e == PAGE.MINE){
  25.     }
  26.   }
  27.   @Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
  28.     Column() {
  29.       Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
  30.         .size({ width: 20, height: 20 }).objectFit(ImageFit.Fill)
  31.       Text(title)
  32.         .fontColor(this.currentIndex === targetIndex ? '#484D54' : '#ff969da9')
  33.         .fontSize(10).margin({top:3,bottom:3})
  34.     }
  35.     .width('100%')
  36.     .height(67)
  37.     .alignItems(HorizontalAlign.Center)
  38.     .backgroundColor('#fff')
  39.     .justifyContent(FlexAlign.Center)
  40.     .onClick(() => {
  41.       this.currentIndex = targetIndex;
  42.       this.tabsController.changeIndex(targetIndex);
  43.     })
  44.   }
  45.   build() {
  46.     Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {
  47.       TabContent() {
  48.         Home()
  49.       }.tabBar(this.TabBuilder('首页', 0, $rawfile('tabs/home_a.png'), $rawfile('tabs/home.png')))
  50.       TabContent() {
  51.         Info()
  52.       }.tabBar(this.TabBuilder('信息', 1, $rawfile('tabs/service_a.png'), $rawfile('tabs/service.png')))
  53.       TabContent() {
  54.         Mine()
  55.       }.tabBar(this.TabBuilder('我的', 2, $rawfile('tabs/me_a.png'), $rawfile('tabs/me.png')))
  56.     }.onChange((index: number) => {
  57.       this.changePage(index)
  58.     })
  59.     .width('100%')
  60.     .height('100%')
  61.   }
  62. }
复制代码

页面切换后怎样加载新数据

介绍

需要留意的是,在tabContent中不管有多少个页面都会被一次性加载完,切换页面不会达到页面更新的效果。那么页面切换后,怎样加载页面的数据呢,很简单,可以利用官方提供的@Link装饰器(父子双向同步)向子组件传递一个时间戳参数过去,页面中使用@Watch监听这个时间戳属性的变革触发自界说的customShow函数。
大概可以增加 if 判定页面索引使其重新加载

父子组件表明

在上述的tabs报告中导入了home页面、info页面、mine页面,那这三个页面就相当于是tabs的子组件了

开始

1.给子组件设置@Link修饰的timer属性(@Link修饰不用赋初值)
2.利用@watch监听一个自界说函数customShow,当父组件的这个timer改变时子组件就会触发这个函数[如图9]
3.父组件Tabs设置三个属性HomeTimer、InfoTimer、MineTimer,分别记录每个页面的时间戳,新增timeStamp函数返回当前时间戳,在changePage函数触发时获取最新的时间戳[如图7],TabContent中页面里传参时别忘了$符号[如图8]。

[图7]

[图8]

[图9]
同样可以自界说页面的烧毁等等,这是我在鸿蒙开发中最常用最省事最高效的办法了,大家不妨试试。

页面切换时可加载新数据的完整代码

Tabs.est
  1. // Tabs.ets
  2. // home页
  3. import Home from '../pages/home/home'
  4. // info页
  5. import Info from '../pages/info/info'
  6. // mine页
  7. import Mine from '../pages/mine/mine'
  8. enum PAGE{
  9.   HOME = 0,
  10.   INFO = 1,
  11.   MINE = 2
  12. }
  13. @Preview
  14. @Component
  15. export default  struct compTabs{
  16.   @State currentIndex: number = 0;
  17.   @State HomeTimer: number = 0;
  18.   @State InfoTimer: number = 0;
  19.   @State MineTimer: number = 0;
  20.   private tabsController: TabsController = new TabsController();
  21.   changePage(e){
  22.     this.currentIndex = e
  23.     if (e == PAGE.HOME){
  24.       this.HomeTimer = this.timeStamp()
  25.     }
  26.     if (e == PAGE.INFO){
  27.       this.InfoTimer = this.timeStamp()
  28.     }
  29.     if (e == PAGE.MINE){
  30.       this.MineTimer = this.timeStamp()
  31.     }
  32.   }
  33.   timeStamp(){
  34.     return new Date().getTime();
  35.   }
  36.   @Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
  37.     Column() {
  38.       Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
  39.         .size({ width: 20, height: 20 }).objectFit(ImageFit.Fill)
  40.       Text(title)
  41.         .fontColor(this.currentIndex === targetIndex ? '#484D54' : '#ff969da9')
  42.         .fontSize(10).margin({top:3,bottom:3})
  43.     }
  44.     .width('100%')
  45.     .height(67)
  46.     .alignItems(HorizontalAlign.Center)
  47.     .backgroundColor('#fff')
  48.     .justifyContent(FlexAlign.Center)
  49.     .onClick(() => {
  50.       this.currentIndex = targetIndex;
  51.       this.tabsController.changeIndex(targetIndex);
  52.     })
  53.   }
  54.   build() {
  55.     Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {
  56.       TabContent() {
  57.         Home({ timer:$HomeTimer })
  58.       }.tabBar(this.TabBuilder('首页', 0, $rawfile('tabs/home_a.png'), $rawfile('tabs/home.png')))
  59.       TabContent() {
  60.         Info({ timer:$InfoTimer })
  61.       }.tabBar(this.TabBuilder('信息', 1, $rawfile('tabs/service_a.png'), $rawfile('tabs/service.png')))
  62.       TabContent() {
  63.         Mine({ timer:$MineTimer })
  64.       }.tabBar(this.TabBuilder('我的', 2, $rawfile('tabs/me_a.png'), $rawfile('tabs/me.png')))
  65.     }.onChange((index: number) => {
  66.       this.changePage(index)
  67.     })
  68.     .width('100%')
  69.     .height('100%')
  70.   }
  71. }
复制代码
home.est
  1. import promptAction from '@ohos.promptAction';
  2. @Component
  3. export default struct Home {
  4.   @State message: string = 'home页面'
  5.   @Link @Watch('customShow') timer: Number
  6.   customShow(){
  7.     promptAction.showToast({
  8.       message: "页面展示"
  9.     });
  10.   }
  11.   build() {
  12.     Row() {
  13.       Column() {
  14.         Text(this.message)
  15.           .fontSize(50)
  16.           .fontWeight(FontWeight.Bold)
  17.       }
  18.       .width('100%')
  19.     }
  20.     .height('100%')
  21.   }
  22. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张裕

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表