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

devtools/2024/10/17 23:04:33/

在开发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.ppmy.cn/devtools/125153.html

相关文章

「实战应用」如何用图表控件LightningChart可视化天气数据?(一)

LightningChart.NET完全由GPU加速,并且性能经过优化,可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D,高级3D,Polar,Smith,3D饼/甜甜圈,地理地图和GIS图表以及适用于科学…

对MVC详细解读

一、MVC模式的详细组成部分 1. 模型(Model) 数据结构: 模型通常使用类或结构来定义应用程序的数据结构。例如,在Ruby on Rails中,模型通常与数据库表相对应,使用Active Record模式。 数据访问层&#xff1…

【AI绘画】Midjourney进阶:三分线构图详解

博客主页: [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 💯前言💯什么是构图为什么Midjourney要使用构图 💯三分线构图特点使用场景提示词书写技巧测试 💯小结 💯前言 【AI绘画】Midjourney进阶&a…

中阳:金融市场中的稳健投资平台

在充满不确定性的全球金融市场中,投资者需要一个既稳健又灵活的平台来应对各种市场挑战。中阳凭借其丰富的市场经验、先进的技术平台和广泛的投资产品,成为了无数投资者信赖的金融合作伙伴。本文将详细介绍中阳的核心优势,帮助投资者在复杂的…

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

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

LeetCode 每日一题 2024/10/7-2024/10/13

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 10/7 871. 最低加油次数10/8 1436. 旅行终点站10/9 3171. 找到按位或最接近 K 的子数组10/10 3162. 优质数对的总数 I10/11 3164. 优质数对的总数 II10/12 3158. 求出出现两…

List的实现类

1.ArrayList(数组) (1)代码 新建学生类: package com.collection;public class Student {private String name;private int age;//添加构造方法 都是使用altenter快捷键public Student() {this.name name;this.age…

蓝桥杯模块三:蜂鸣器和继电器的基本控制

模块训练题目: 一、蜂鸣器电路图 1.电路图 2.电路分析 138译码器控制Y5,Y5控制Y5C,Y5C低电平控制芯片开启P0口控制ULN2003继而控制蜂鸣器端口和继电器端口 二、程序代码 1.138译码器控制端口函数 建立初始化函数选择锁存器 2.实现题目功能 在LED代…