HarmonyOS NEXT 应用开发实战(三、ArkUI页面底部导航TabBar的实现)

在开发HarmonyOS NEXT应用时,TabBar是用户界面设计中不可或缺的一部分。本文将通过代码示例,带领大家一同实现一个常用的TabBar,涵盖三个主要的内容页:首页、知乎日报和我的页面。以模仿知乎日报的项目为背景驱动,设定一个小目标,最终实现知乎日报app项目。

1. 项目结构

在我们的代码中,首先需要导入需要使用的页面组件:

import Home from "../pages/home/Home"
import ZhiHu from "../pages/zhihu/Zhihu"
import Mine from "../pages/mine/Mine"

这三条语句确保我们可以在TabBar中使用这些页面,分别是首页,知乎日报页和个人中心页。

关于Tabs组件的官方文档:文档中心-Tabs导航组件 

2. 代码实现

接下来,我们将实现一个名为Index的组件,这是整个TabBar的核心。在此组件中,我们定义了三个主要功能:

  • 页面显示的生命周期管理
  • TabBar的构建与展示
  • 自定义Tab项样式

2.1 页面生命周期管理

我们定义了一些生命周期函数,帮助我们在页面显示和隐藏时输出相应的信息:

@Entry
@Component
struct Index {
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController()

  onPageShow() {
    console.info('Index onPageShow');
  }

  onPageHide() {
    console.info('Index onPageHide');
  }

  onBackPress() {
    console.info('Index onPageBackPress');
  }

currentIndex用于跟踪当前选中的Tab项,而controller则用于控制Tab的切换。

2.2 构建TabBar

在组件的build方法中,我们使用Tabs组件来创建TabBar,添加每个Tab项的内容和样式配置:

build() {
  Column() {
    Tabs({
      barPosition: BarPosition.End,
      controller: this.controller
    }) {
      TabContent() {
        Home()
      }.tabBar(this.TabBuilder('首页', 0, $r('app.media.icon_sort'), $r('app.media.icon_sort_default')))

      TabContent() {
        ZhiHu()
      }.tabBar(this.TabBuilder('日报', 1, $r('app.media.search_select'), $r('app.media.search_default')))

      TabContent() {
        Mine()
      }.tabBar(this.TabBuilder('我的', 2, $r('app.media.user_selected'), $r('app.media.user')))
    }.scrollable(false) // 禁止滑动切换
  }
  .width('100%')
  .height('100%')
}

这里使用了TabContent来表示每个页面的具体内容,并通过tabBar来定义每个Tab的样式和功能。

每一个TabContent对应的内容需要有一个页签,可以通过TabContent的tabBar属性进行配置。在如下TabContent组件上设置属性tabBar,可以设置其对应页签中的内容,tabBar作为内容的页签。

设置多个内容时,需在Tabs内按照顺序放置。

导航栏位置使用Tabs的参数barPosition进行设置,默认情况下,导航栏位于顶部,参数默认值为Start。设置为底部导航需要在Tabs传递参数,设置barPosition为End。

对应的图片资源,需放置在entry\src\main\resources\base\media目录中。这里发现个问题,图片只能放在这,好像里面不能再建子文件夹目录了,也就是说图片资源混在一起,这点儿有点儿不太好。

2.3 自定义Tab项样式

接下来,我们自定义了一个名为TabBuilder的方法,以便我们可以灵活地构建每个Tab的样式:

@Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
  Column() {
    Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
      .size({ width: 25, height: 25 })
    Text(title)
      .fontColor(this.currentIndex === targetIndex ? '#28bff1' : '#8a8a8a')
  }
  .width('100%')
  .height(50)
  .justifyContent(FlexAlign.Center)
  .onClick(() => {
    this.currentIndex = targetIndex
    this.controller.changeIndex(this.currentIndex)
  })
}

这个构建器根据当前选中的Tab来设置图标和文字颜色,并在点击时更新currentIndex和Tab的显示状态。

在page目录下新建文件夹home,mine和zhihu分别用来存放对应的tab页的内容。这样便于清晰的管理各个页面,且不至于把所有内容都放到一个Index.ets文件里。对应的主页Home组件,内容举例如下:


@Component
export default struct Home {
  build() {
    Column() {
      // 标题栏
      Text("首页")
        .size({ width: '100%', height: 50 })
        .backgroundColor("#28bff1")
        .fontColor("#ffffff")
        .textAlign(TextAlign.Center)
        .fontSize("18fp")
      // 内容项
      Text("首页").width('100%').height('100%').textAlign(TextAlign.Center).fontSize("25fp")
    }.size({ width: '100%', height: '100%' })
  }
}

3. 完整实现

import Home from "../pages/home/Home"
import ZhiHu from "../pages/zhihu/Zhihu"
import Mine from "../pages/mine/Mine"

@Entry
@Component
struct Index {
  @State currentIndex: number = 0
  private controller: TabsController = new TabsController()

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageShow() {
    console.info('Index onPageShow');
  }
  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageHide() {
    console.info('Index onPageHide');
  }

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onBackPress() {
    console.info('Index onBackPress');
  }

  build() {
    Column() {
      Tabs({
        barPosition: BarPosition.End,
        controller: this.controller
      }) {
        TabContent() {
          Home()
        }.tabBar(this.TabBuilder('首页', 0, $r('app.media.icon_sort'), $r('app.media.icon_sort_default')))

        TabContent() {
          ZhiHu()
        }.tabBar(this.TabBuilder('日报', 1, $r('app.media.search_select'), $r('app.media.search_defaut')))

        TabContent() {
           Mine()
        }.tabBar(this.TabBuilder('我的', 2, $r('app.media.user_selected'), $r('app.media.user')))
      }.scrollable(false) // 禁止滑动切换
    }
    .width('100%')
    .height('100%')
  }

  // 自定义导航页签的样式
  @Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
        .size({ width: 25, height: 25 })
      Text(title)
        .fontColor(this.currentIndex === targetIndex ? '#28bff1' : '#8a8a8a')
    }
    .width('100%')
    .height(50)
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      this.currentIndex = targetIndex
      this.controller.changeIndex(this.currentIndex)
    })
  }
}

4. 总结

通过上述步骤,我们在HarmonyOS NEXT的应用中成功实现了一个简单的TabBar。这个TabBar包含了三个功能模块,并能够根据用户的操作进行动态更新。接下来,您可以在此基础上,进一步扩展更多功能,提升用户体验。希望这篇博文能够对您在HarmonyOS应用开发中有所帮助。

写在最后

最后,推荐下笔者的业余开源app影视项目“爱影家”,推荐分享给与我一样喜欢观影的朋友。

开源地址:爱影家app开源项目介绍及源码

https://gitee.com/yyz116/imovie

其他资源

HarmonyOS 鸿蒙应用开发( 五、快速实现ArkUI页面底部导航Tabs)_鸿蒙开发底部导航-CSDN博客

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

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

相关文章

JavaScript reduce() 函数原理及应用

一. 引言 在 JavaScript 开发中,我们经常需要对数组中的元素进行统计、计算或转换,以便得到我们需要的结果。在这个过程中,reduce() 函数成为了一个非常有用的工具。reduce() 函数让我们能够以一种简洁而优雅的方式对数组中的元素进行累积计…

FFMpeg源码分析,关键结构体分析(一)

http://lazybing.github.io/blog/categories/ffmpegyuan-ma-fen-xi/ 一、下载FFmpeg的编译源码 进入网站:http://ffmpeg.org/download.html二、编译源码 执行下述命令: ./configure --prefix/usr/local/ffmpeg --enable-debug3 --enable-ffplay sudo …

Redis主从复制机制详解

目录 一、主从复制介绍二、搭建主从复制三、主从复制流程四、关于Replication ID五、主从复制核心知识六、主从复制应用场景七、主从复制的注意事项八、读写分离实战 一、主从复制介绍 1、什么是主从复制? 2、为什么要使用主从复制? redis-server单点…

谷歌浏览器 文件下载提示网络错误

情况描述: 谷歌版本:129.0.6668.90 (正式版本) (64 位) (cohort: Control)其他浏览器,比如火狐没有问题,但是谷歌会下载失败,故推断为谷歌浏览器导致的问题小文件比如1、2M会成功,大…

【问题分析】使用gperftools分析排查内存问题

背景 当程序长时间允许时(压测、服务器程序),就会面临更大的挑战,其中内存泄漏就是一类典型的问题,内存泄漏往往不易发现,导致的现象更是千奇百怪,本文主要介绍如何借助gperftools分析一个模块的内存泄漏 案例代码 …

yum仓库安装rabbitmq

yum仓库安装rabbitmq 1、配置yum仓库 vim /etc/yum.repos.d/rabbitmq.repo # In /etc/yum.repos.d/rabbitmq.repo## ## Zero dependency Erlang ##[rabbitmq_erlang] namerabbitmq_erlang baseurlhttps://packagecloud.io/rabbitmq/erlang/el/7/$basearch repo_gpgcheck1 gpg…

软件工程:需求规格说明书(图书管理系统)

目录 1 导言 1.1 编写目的 1.2 参考资料 2 项目介绍 2.1 项目背景 2.2 项目目标 3 应用环境 3.1 系统运行网络环境 ​编辑 3.2 系统软硬件环境 4 功能模型 4.1 功能角色分析 4.1.1 图书管理员 4.1.2 普通读者 4.1.3 邮件系统 4.2 功能性需求 4.2.1 预定图…

【一步步开发AI运动小程序】二十、AI运动小程序如何适配相机全屏模式?

引言 受小程序camera组件预览和抽帧图像不一致的特性影响,一直未全功能支持全屏模式,详见本系列文件第四节小程序如何抽帧;随着插件在云上赛事、健身锻炼、AI体测、AR互动场景的深入应用,各开发者迫切的希望能在全屏模式下应用&am…

Excel中Ctrl+e的用法

重点:想要使用ctrle,前提是整合或拆分后的结果放置的单元格必须和被提取信息的单元格相邻,且被提取信息的单元格也必须相连。 下图为错误示例 这样则可以使用ctrle 1、信息整合 2、提取信息 3、添加符号 4、信息顺序调换 5、数字提取 crtle还…

Vue3 + Element plus 实现切换el-radio前二次确认

Vue3 Element plus 实现切换el-radio前二次确认 场景:点击切换el-radio之前判断当前内容是否有改变,如有改变弹窗提示切换el-radio将销毁操作,弹窗二次确认是否切换 问题: el-radio 没有提供类似于beforeUpdate这样的钩子去处理这…

手写mybatis之细化XML语句构建器,完善静态SQL解析

前言 1:在流程上,通过 DefaultSqlSession#selectOne 方法调用执行器,并通过预处理语句处理器 PreparedStatementHandler 执行参数设置和结果查询。 2:那么这个流程中我们所处理的参数信息,也就是每个 SQL 执行时&#…

基于yolov10的芒果成熟度检测系统,支持图像、视频和摄像实时检测【pytorch框架、python】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示: yolov10,芒果成熟度检测系统,支持图像、视频和摄像实时检测【pytorch框架、python】_哔哩哔哩_bilibili (一)简介 基于yolov10的芒果成熟度检测系统是…

npm install报错一堆sass gyp ERR!

执行npm install ,出现一堆gyp含有sass错误的情况下。 解决办法: 首页可能是node版本问题,太高或者太低,也会导致npm install安装错误(不会自动生成node_modules文件),本次试验,刚开…

【JavaEE】——初始网络原理

阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:局域网 1:概念 二:局域网的连接方式 1:网线直连 …

flask项目框架搭建

目录结构 blueprints python包,蓝图文件,相当于路由组的概念,方便模块化开发 例如auth.py文件 from flask import Blueprint, render_templatebp Blueprint("auth", __name__, url_prefix"/auth")bp.route("/login") d…

空间解析几何3-空间点到线段和平面的距离【附MATLAB代码】

目录 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 function [dis,P2,t] point2Line (A1,B1,C1) %求空间一点到一线段的最短距离 %[dis,P2,Q2]pointSegmentDistance(A,B,C) %A B为线段首末端…

问卷调查毕设计算机毕业设计投票系统SpringBootSSM框架

目录 一、引言‌ ‌二、需求分析‌ 用户角色‌: ‌功能需求‌: ‌非功能需求‌: ‌三、系统设计‌ ‌技术选型‌: ‌数据库设计‌: ‌界面设计‌: ‌四、实现步骤‌ ‌后端实现‌: …

蓝桥杯【物联网】零基础到国奖之路:十八. 扩展模块之光敏和AS312

蓝桥杯【物联网】零基础到国奖之路:十八.扩展模块之光敏和AS312 第一节 硬件解读第二节 CubeMX配置第二节 代码 第一节 硬件解读 光敏和AS312如下图: 光敏电阻接到了扩展模块的5号引脚,5号引脚接了2个电阻,R8和光敏电阻。我们通过ADC读取这…

vue+ElementUI—实现基础后台管理布局(sideBar+header+appMain)(附源码)

后台管理的模板很多,vue本身就提供了完整的vue-template-admin,vue-admin-beautiful等后台管理系统化框架,但是这些框架正是因为成体系而显得繁重。假如你想搭建一个静态的后台管理模板页面和几个单独的菜单页面,直接就上框架是否…

维生素对于生活的重要性

在探索健康奥秘的旅途中,维生素作为人体不可或缺的微量营养素,扮演着至关重要的角色。它们虽不直接提供能量,却是酶促反应、细胞代谢、免疫功能乃至心理健康的基石。今天,让我们一同深入探讨人体所需补充的维生素,这些…