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 = 0private 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 = targetIndexthis.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 = 0private 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 = targetIndexthis.controller.changeIndex(this.currentIndex)})}
}

4. 总结

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

写在最后

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

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

https://gitee.com/yyz116/imovie

其他资源

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决ubuntu 下 VS code 无法打开点击没反应问题

从Ubuntu 22.04 升级到ubuntu 24.04 后,发现Vsode无法打开,不论是点击图标,还是terminator里面运行code 可执行程序,均没有反应。debug如下: 提示权限不够。 解决方案: sudo sysctl -w kernel.apparmor_restrict_unp…

C语言题目练习2

前面我们知道了单链表的结构及其一些数据操作,今天我们来看看有关于单链表的题目~ 移除链表元素 移除链表元素: https://leetcode.cn/problems/remove-linked-list-elements/description/ 这个题目要求我们删除链表中是指定数据的结点,最终返…

C语言 | Leetcode C语言题解之第460题LFU缓存

题目: 题解: /* 数值链表的节点定义。 */ typedef struct ValueListNode_s {int key;int value;int counter;struct ValueListNode_s *prev;struct ValueListNode_s *next; } ValueListNode;/* 计数链表的节点定义。 其中,head是数值链表的头…

腾讯云Android 与 iOS 相关

移动端(Android/iOS)支持哪几种系统音量模式? 支持2种系统音量类型,即通话音量类型和媒体音量类型: 通话音量:手机专门为通话场景设计的音量类型,使用手机自带的回声抵消功能,音质…

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

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

【LeetCode】动态规划—95. 不同的二叉搜索树 II(附完整Python/C++代码)

动态规划—95. 不同的二叉搜索树 II 题目描述前言基本思路1. 问题定义二叉搜索树的性质: 2. 理解问题和递推关系递归构造思想:状态定义:递推公式:终止条件: 3. 解决方法递归 动态规划方法:伪代码&#xff…

如何使用vscode的launch.json来debug调试

1、创建一个launch.json文件 选择Python Debugger,再选择Python文件,创建处理如下 默认有下面五个参数 "name": "Python Debugger: Current File","type": "debugpy","request": "launch"…

金九银十软件测试面试题(800道)

今年你的目标是拿下大厂offer?还是多少万年薪?其实这些都离不开日积月累的过程。 为此我特意整理出一份(超详细笔记/面试题)它几乎涵盖了所有的测试开发技术栈,非常珍贵,人手一份 肝完进大厂 妥妥的&#…

【LeetCode】动态规划—123. 买卖股票的最佳时机 III(附完整Python/C++代码)

动态规划—123. 买卖股票的最佳时机 III 题目描述前言基本思路1. 问题定义2. 理解问题和递推关系状态定义:状态转移公式:初始条件: 3. 解决方法动态规划方法伪代码: 4. 进一步优化5. 小总结 Python代码Python代码解释 C代码C代码解…

Python基础之List列表用法

1、创建列表 names ["张三","李四","王五","Mary"] 2、列表分片 names[1]:获取数组的第2个元素。 names[1:3]:获取数组的第2、第3个元素。包含左侧,不包含右侧。 names[:3]等同于names[0:3]&…

List子接口

1.特点:有序,有下标,元素可以重复 2.方法:包含Collection中的所有方法,还包括自己的独有的方法(API中查找) 还有ListIterator(迭代器),功能更强大。 包含更多…

机器学习/数据分析--用通俗语言讲解时间序列自回归(AR)模型,并用其预测天气,拟合度98%+

时间序列在回归预测的领域的重要性,不言而喻,在数学建模中使用及其频繁,但是你真的了解ARIMA、AR、MA么?ACF图你会看么?? 时间序列数据如何构造???,我打过不少…

读书笔记 - 虚拟化技术 - 0 QEMU/KVM概述与历史

《QEMU/KVM源码解析与应用》 - 王强 概述 虚拟化简介 虚拟化思想 David Wheeler:计算机科学中任何问题都可以通过增加一个中间层来解决。 虚拟化思想存在与计算机科学的各个领域。 主要思想:通过分层将底层的复杂,难用的资源虚拟抽象为简…

Spring Cloud 3.x 集成eureka快速入门Demo

1.什么是eureka? Eureka 由 Netflix 开发,是一种基于REST(Representational State Transfer)的服务,用于定位服务(服务注册与发现),以实现中间层服务的负载均衡和故障转移&#xff…

day01-Qt5入门

day01-Qt5入门 窗体应用 1.1 窗体基类说明 创建项目在details中编辑器提供了三个基类,分别是 QMainWindows、Qwidget、QDialog 1、 QMainWindow QMainWindow 类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用 程序窗口。…

Java-基础

1. 导入模块不能纯粹的复制粘贴,要从new里导入,因为前者建立不了关联 2. 数组 String[] name{"张三","李四","王五"};int[] numsnew int[]{1,2,3};//二维String[][] names{{"张三","李四"},{"…

RT-DETR改进策略:BackBone改进|CAFormer在RT-DETR中的创新应用,显著提升目标检测性能

摘要 在目标检测领域,模型性能的提升一直是研究者和开发者们关注的重点。近期,我们尝试将CAFormer模块引入RT-DETR模型中,以替换其原有的主干网络,这一创新性的改进带来了显著的性能提升。 CAFormer,作为MetaFormer框架下的一个变体,结合了深度可分离卷积和普通自注意力…

MATLAB - 机械臂手眼标定(眼在手内) - 估计安装在机器人上的移动相机的姿态

系列文章目录 前言 本示例展示了如何为装有手眼构型摄像头的机械臂或机械手执行和验证手眼校准。 一、概述 执行手眼校准有助于操作配备末端执行器(简称 “手”)的机械臂,该末端执行器依赖于摄像头提供的视觉数据。一旦完成了眼在手外的校准&…

LabVIEW 成绩统计系统

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

中科星图GVE(案例)——AI实现建筑用地变化前后对比情况

目录 简介 函数 gve.Services.AI.ConstructionLandChangeExtraction(image1,image2) 代码 结果 知识星球 机器学习 简介 AI可以通过分析卫星图像、航拍影像或其他地理信息数据,实现建筑用地变化前后对比。以下是一种可能的实现方法: 数据获取&am…