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

news2024/12/28 5:04:52

在开发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.coloradmin.cn/o/2209979.html

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

相关文章

【Spring AI】Java实现类似langchain的第三方函数调用_原理与详细示例

Spring AI 介绍 :简化Java AI开发的统一接口解决方案 在过去,使用Java开发AI应用时面临的主要困境是没有统一且标准的封装库,导致开发者需要针对不同的AI服务提供商分别学习和对接各自的API,这增加了开发难度与迁移成本。而Sprin…

Android常用界面控件——ProgressBar

ProgressBar 目录 ProgressBar 在XML中定义ProgressBar ProgressBar风格样式 ProgressBar常用XML属性 在Java代码中控制ProgressBar 实例 什么是ProgressBar? ProgressBar是Android中的一个视图控件,主要用于表示一个任务的进度情况,…

针对Ubuntu20.04 中的 Docker 配置可用镜像源(包含国内可用镜像源)

文章目录 写在前面一、Docker 官方源二、更换Docker 国内可用镜像源 (推荐使用)参考链接 写在前面 自己的测试环境: Ubuntu20.04,docker-27.3.1 一、Docker 官方源 打开 /etc/docker/daemon.json文件: sudo gedit …

Python快速编程小案例--逢7拍手小游戏

提示:(个人学习),案例来自工业和信息化“十三五”人才培养规划教材,《Python快速编程入门》第2版,黑马程序员◎编著 逢7拍手游戏的规则是:从1开始顺序数数,数到有7或者包含7的倍数的…

查缺补漏----时间复杂度

1.如果每一次循环变量都是,那么直接将每一层变量的最大遍历次数相乘 第一个代码段:O(n^3) 第二个代码段:O(n*i*j),由于 i 的范围0~n-1,所以取n,j 同理,所以最…

Java | Leetcode Java题解之第473题火柴拼正方形

题目&#xff1a; 题解&#xff1a; class Solution {public boolean makesquare(int[] matchsticks) {int totalLen Arrays.stream(matchsticks).sum();if (totalLen % 4 ! 0) {return false;}int len totalLen / 4, n matchsticks.length;int[] dp new int[1 << n…

【hot100-java】从前序与中序遍历序列构造二叉树

二叉树篇 首先创建一个映射来存储中序遍历中值与索引的关系&#xff0c;然后通过递归调用函数dfs来构建二叉树。函数dfs接受前序遍历和中序遍历的左右边界索引以及前序遍历和中序遍历的列表和映射作为参数&#xff0c;在每次递归中&#xff0c;先判断边界条件&#xff0c;如果左…

部署 Open WebUI

1. 安装docker 2.启动Hyper-v 3.下载 安装 WSL 4. 打开 DeskDocker 5. 打开 运行 ollama 参考 Windows 部署 ollama-CSDN博客 6. 部署 运行 open webui docker docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gateway -v open-webui:/app/backend/data -…

Flutter Transform 学习

Transform可以在其子组件绘制时对其应用一些矩阵变换来实现一些特效,允许在渲染子部件之前对它们进行变换。 一、Transform构造函数与属性 class Transform extends SingleChildRenderObjectWidget {/// Creates a widget that transforms its child.const Transform({super.k…

C语言 | 第十六章 | 共用体 家庭收支软件-1

P 151 结构体定义三种形式 2023/3/15 一、创建结构体和结构体变量 方式1-先定义结构体&#xff0c;然后再创建结构体变量。 struct Stu{ char *name; //姓名 int num; //学号 int age; //年龄 char group; //所在学习小组 float score; //成绩 }; struct Stu stu1, stu2; //…

InternVL2-40B 荣登开源模型榜首丨SuperCLUE中文多模态大模型基准10月榜单

在今年 7 月 4 日举行的 2024 WAIC 科学前沿主论坛上&#xff0c;书生万象多模态大模型&#xff08;InternVL 2.0&#xff09;正式发布&#xff0c;并陆续开源了 1B、2B、4B、8B、26B、40B 以及 76B 共 7 个参数版本的模型。书生万象支持图像、视频、文字、语音、三维点云等模态…

Qt媒体播放器实现

本文介绍Qt媒体播放器实现。 Qt应用程序有时会涉及到视频文件的播放&#xff0c;Qt提供了QVideoWidget类实现视频和音频的播放&#xff0c;本文基于QVideoWidget类实现一个简单的媒体播放器。 1.自定义类&#xff08;基于QVideoWidget类&#xff09; 由于Qt并未提供专门的控…

手写简易shell

我们如果要写一个简易的shell我们要&#xff0c;其实我们搞一个程序替换就行了。 我们分为五部完成 在其中我们最难搞的就是环境变量的更新&#xff0c;因为当我们搞一个子程序出来时&#xff0c;我们子进程的环境变量表是从父进程继承下来的&#xff0c;当我们用cd命令时只会更…

C# 屏幕录制工具

屏幕录制工具 开发语音&#xff1a;C# vb.net 下载地址&#xff1a;https://download.csdn.net/download/polloo2012/89879996 功能&#xff1a;屏幕录制&#xff0c;声卡采集&#xff0c;麦克风采集。 屏幕录制&#xff1a;录制屏幕所有操作&#xff0c;并转换视频格式&…

电脑无线网wifi和有线网同时使用(内网+外网同时使用)

一、要求 我这里以无线网wifi为外网&#xff0c;有线网卡为内网为例&#xff1a; 一、基本信息 无线wifi&#xff08;外网&#xff09;&#xff1a;ip是192.168.179.235&#xff0c;网关是192.168.179.95有线网&#xff08;内网&#xff09;&#xff1a;ip是192.168.10.25&…

《鸟哥的Linux私房菜基础篇》---1 Linux的介绍与如何开启Linux之路

目录 一、Linux的简单介绍 1、Linux的简介 2、Linux的起源与发展 3、主要特点 4、应用场景 二、开启Linux之路 1、学习Linux的相关知识 2、正规表示法、管线命令、数据流重导向 前言 整体大纲预览 一、Linux的简单介绍 1、Linux的简介 &#xff08;1&#xff09;Linu…

【Trulens框架】用TruLens 自动化 RAG 应用项目评估测试

前言&#xff1a; 什么是Trulens TruLens是面向神经网络应用的质量评估工具&#xff0c;它可以帮助你使用反馈函数来客观地评估你的基于LLM&#xff08;语言模型&#xff09;的应用的质量和效果。反馈函数可以帮助你以编程的方式评估输入、输出和中间结果的质量&#xff0c;从而…

K8S---01初识Kubernetes

一.简介 摘取官网: 概述 | KubernetesKubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;方便进行声明式配置和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统&#xff0c;其服务、支持和工具的使用范围广泛。https://k…

【C++堆(优先队列)】1882. 使用服务器处理任务|1979

本文涉及知识点 C堆(优先队列) LeetCode1882. 使用服务器处理任务 给你两个 下标从 0 开始 的整数数组 servers 和 tasks &#xff0c;长度分别为 n​​​​​​ 和 m​​​​​​ 。servers[i] 是第 i​​​​​​​​​​ 台服务器的 权重 &#xff0c;而 tasks[j] 是处理…

【寻找one piece的算法之路】前缀和(一)

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;寻找one piece的刷题之路 什么是前缀和&#xff1f; 主要是通过预先计算数组或矩阵的前缀和&#xff0c;来快速查询子数组或子矩阵的和。这种算法可以用空间换时间&#xff0c;提高查询效率。 概念…