HarmonyOs开发:导航tabs组件封装与使用

前言

主页的底部导航以及页面顶部的切换导航,无论哪个系统,哪个App,都是最常见的功能之一,虽然说在鸿蒙中有现成的组件tabs可以很快速的实现,但是在使用的时候,依然有几个潜在的问题存在,第一,当导航较少时,tabs是默认居中模式,目前无法进行居左,在有这样功能的时候,难以满足需求;第二,导航右侧需要展示按钮的时候,tabs也是无法满足的;除此之外,还有很多人都非常关心的问题,底部的指示器可以跟随页面的滑动而滑动;面对着种种问题的存在,系统的tabs改进之路仍然很艰巨。

本篇的文章内容如下:

1、封装tabs效果及基本使用

2、主要的封装实现分析

3、开源地址

4、相关总结

一、封装tabs效果及基本使用

所有的效果都是基于tabs组件进行拓展的。

(功能项)

(底部Tab)

(普通导航)

(居左导航)

(右边按钮)

以上就是封装后的部分效果,目前已经上传到了远程仓库,大家可以按照以下的方式进行使用。

方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。

ohpm install @abner/tab

方式二:在工程的oh-package.json5中设置三方包依赖,配置示例如下:

"dependencies": { "@abner/tab": "^1.0.0"}

1、底部导航案例

相关效果:

代码实现:


@Entry
@Component
struct BottomTabPage1 {/*** AUTHOR:AbnerMing* INTRODUCE:tab对应的页面* @param index 索引* @param item TabBar对象,非必须* */@BuilderitemPage(index: number, item: TabBar) {Text(item.title)}build() {Column() {ActionBar({ title: "底部导航案例一" })BottomTabLayout({itemPage: this.itemPage,//tab对应的页面tabSelectedColor: "#D81E06",//文字未选择颜色tabNormalColor: Color.Black,//文字未选择颜色tabLabelMarginTop: 10,//文字距离图片的高度tabScrollable: true,//是否可以滑动tabMarginBottom: 30, //距离底部的距离,一般可以获取底部导航栏的高度,然后进行设置onChangePage: (position) => {//页面切换},onTabBarClick: (position) => {//tab点击},tabBar: [new TabBar("首页", $r("app.media.ic_home_select"), $r("app.media.ic_home_unselect")),new TabBar("网络", $r("app.media.ic_net_select"), $r("app.media.ic_net_unselect")),new TabBar("列表", $r("app.media.ic_list_select"), $r("app.media.ic_list_unselect")),new TabBar("组件", $r("app.media.ic_view_select"), $r("app.media.ic_view_unselect"))]})}.height("100%")
}
}

相关属性

属性

类型

概述

itemPage

BuilderParam

tab对应得页面

tabSelectedColor

ResourceColor

tab选中颜色

tabNormalColor

ResourceColor

tab未选中颜色

tabSelectedBgColor

ResourceColor

选中背景颜色

tabNormalBgColor

ResourceColor

未选中背景颜色

tabIconWidth

number

图片icon的宽度,默认20

tabIconHeight

number

图片icon的高度,默认20

tabSize

number

tab文字大小

tabWeight

number /FontWeight / string

文字权重

tabLabelMarginTop

number

标签距离图片的高度

tabBar

Array<TabBar>

tab数据源

tabWidth

Length

tab指示器的宽度

tabHeight

number

tab指示器的高度,默认56

currentIndex

number

当前索引,默认是第一个

onChangePage

回调方法

页面切换监听

onTabBarClick

tab点击回调

tab点击监听

tabScrollable

boolean

是否可滑动,默认不可以滑动

tabMarginBottom

number

tab距离底部的距离

2、底部导航案例2,自定义Tab视图

相关效果:

代码实现:

@Entry
@Component
struct BottomTabPage2 {private currentIndex = 0 //默认是第一个/*** AUTHOR:AbnerMing* INTRODUCE:tab对应的页面* @param index 索引* @param item TabBar对象,非必须* */@BuilderitemPage(index: number, item: TabBar) {Text(item.title)}/*** AUTHOR:AbnerMing* INTRODUCE:自定义Tab视图,自己绘制* @param index 索引* @param item TabBar对象,非必须* */
@Builder
itemTab(index: number, item: TabBar) {Column() {Image(this.currentIndex == index ? item.selectedIcon: item.normalIcon).width(30).height(30)Text(item.title).fontColor(this.currentIndex == index ? "#D81E06" : "#000000").fontSize(14).margin({ top: 5 })}.width("100%")
}build() {Column() {ActionBar({ title: "底部导航案例二" })BaseBottomTabLayout({itemPage: this.itemPage,itemTab: this.itemTab,tabBar: [new TabBar("首页", $r("app.media.ic_home_select"), $r("app.media.ic_home_unselect")),new TabBar("网络", $r("app.media.ic_net_select"), $r("app.media.ic_net_unselect")),new TabBar("列表", $r("app.media.ic_list_select"), $r("app.media.ic_list_unselect")),new TabBar("组件", $r("app.media.ic_view_select"), $r("app.media.ic_view_unselect"))],tabMarginBottom: 30, //距离底部的距离,一般可以获取底部导航栏的高度,然后进行设置onTabBarClick: (position) => {//tab点击console.log("====点击了Tab" + position)},onChangePage: (position) => {//页面切换console.log("====页面切换了" + position)}})}
}
}

相关属性

属性

类型

概述

itemPage

BuilderParam

tab对应得页面

tabSelectedColor

ResourceColor

tab选中颜色

tabNormalColor

ResourceColor

tab未选中颜色

tabSelectedBgColor

ResourceColor

选中背景颜色

tabNormalBgColor

ResourceColor

未选中背景颜色

tabIconWidth

number

图片icon的宽度,默认20

tabIconHeight

number

图片icon的高度,默认20

tabSize

number

tab文字大小

tabWeight

number /FontWeight / string

文字权重

tabLabelMarginTop

number

标签距离图片的高度

tabBar

Array<TabBar>

tab数据源

tabWidth

Length

tab指示器的宽度

tabHeight

number

tab指示器的高度,默认56

currentIndex

number

当前索引,默认是第一个

onChangePage

回调方法

页面切换监听

onTabBarClick

tab点击回调

tab点击监听

tabScrollable

boolean

是否可滑动,默认不可以滑动

tabMarginBottom

number

tab距离底部的距离

isMarginBottom

boolean

默认开启,tab距离底部的距离

3、普通指示器导航

相关效果:

代码实现:

@Entry
@Component
struct TabLayoutPage1 {@BuilderitemPage(index: number, item: string) {Text(item)}build() {Column() {ActionBar({ title: "封装导航【普通】" })TabLayout({tabBar: ["条目一", "条目二"],itemPage: this.itemPage,tabAttribute: (tab) => {//设置属性},onChangePage: (position) => {//页面改变console.log("页面改变:" + position)},onTabBarClick: (position) => {//点击改变console.log("点击改变:" + position)}})}}
}

相关属性

属性

类型

概述

tabWidth

Length

tab指示器的宽度

tabHeight

number

tab指示器的高度

onChangePage

回调方法(position: number)

页面改变回调

currentIndex

number

当前索引,默认第0个

tabScrollable

boolean

是否可以滑动切换页面,默认可以滑动

tabBar

Array<string>

数据源

itemPage

回调方法BuilderParam (index: number, item: string)

tab对应得页面

tabAttribute

回调方法(attribute: TabModel)

设置tab相关属性

isHideDivider

boolean

是否隐藏下划线,默认展示

isTabAlignLeft

boolean

是否从最左边开始,默认不是

barMode

BarMode

是均分还是可滑动,默认滑动

onTabBarClick

回调方法(position: number)

tab点击回调

isShowTabMenu

boolean

是否展示右边的按钮选项,默认不展示

tabMenu

回调方法BuilderParam

右边展示的按钮视图

tabMenuWidth

number

tab右侧按钮的宽度

tabMenuMarginRight

number

tab按钮距离右侧的距离

4、普通指示器导航【均分】

相关效果:

代码实现:

@Entry
@Component
struct TabLayoutPage2 {@BuilderitemPage(index: number, item: string) {Text(item)}build() {Column() {ActionBar({ title: "封装导航【均分】" })TabLayout({tabBar: ["条目一", "条目二", "条目三", "条目四"],barMode: BarMode.Fixed, //均分itemPage: this.itemPage,tabAttribute: (tab) => {//设置属性},onChangePage: (position) => {//页面改变console.log("页面改变:" + position)},onTabBarClick: (position) => {//点击改变console.log("点击改变:" + position)}})}}
}

相关属性

同上。

5、普通指示器导航【居左】

相关效果:

代码实现:

@Entry
@Component
struct TabLayoutPage4 {@BuilderitemPage(index: number, item: string) {Text(item)}build() {Column() {ActionBar({ title: "封装导航【居左】" })TabLayout({tabBar: ["条目一", "条目二"],isTabAlignLeft: true,itemPage: this.itemPage,tabAttribute: (tab) => {//设置属性},onChangePage: (position) => {//页面改变console.log("页面改变:" + position)}})}}
}

相关属性

同上。

6、普通指示器导航【右边添加按钮】

相关效果:

代码实现:

@Entry
@Component
struct TabLayoutPage6 {@BuilderitemPage(index: number, item: string) {Text(item)}/*** AUTHOR:AbnerMing* INTRODUCE:右侧的按钮,可以是任何的视图* */@BuilderitemMenu() {Text("测试").backgroundColor(Color.Pink).width("100%").height("100%").textAlign(TextAlign.Center)}build() {Column() {ActionBar({ title: "封装导航【居左滑动】" })TabLayout({tabBar: ["条目一", "条目二", "条目三", "条目四", "条目五", "条目六"],isTabAlignLeft: true,itemPage: this.itemPage,isShowTabMenu: true, //展示右侧的按钮tabMenu: this.itemMenu, //按钮tabMenuWidth: 100, //按钮宽度tabAttribute: (tab) => {//设置属性},onChangePage: (position) => {//页面改变console.log("页面改变:" + position)}})}}
}

相关属性

同上。

二、主要的封装实现分析

大部分的封装都是基于系统提供的Api实现的,无非就是简化了相关代码,基本上都不难,大家可以直接查看源码即可,这里重点说下普通导航的居左效果。

在文章开头的时候已经阐述,目前的tabs是不支持居左的,如果要实现居左的效果,就要自己自定义,这里使用的是横向的List组件实现的,通过Scroller来控制滑动距离。

List({ scroller: this.scroller }) {ForEach(this.tabBar, (item: string, index: number) => {ListItem() {this.tabItem(index, item)}.height(this.tabHeight).onClick(() => {//条目点击if (this.isTabAlignLeft) {//自定义滑动if (index > this.currentIndex) {this.scroller.scrollBy(20 * (index + 1), 0)} else {this.scroller.scrollBy(-20 * (this.tabBar.length - index), 0)}}this.currentIndex = index})}, (item: string) => item)}.listDirection(Axis.Horizontal).width(this.tabListWidth).height(this.tabHeight).scrollBar(BarState.Off)

需要注意的是,如果采用居左的效果,那么系统的tabBar我们就要舍弃,如下代码,如果居左,采用上述自定义tabBar,否则采用系统自定义的。

//使用tabBar对象形式传递if (this.isTabAlignLeft) {ForEach(this.tabBar, (item: string, index) => {TabContent() {this.itemPage(index, item)}})} else {ForEach(this.tabBar, (item: string, index) => {TabContent() {this.itemPage(index, item)}.tabBar(this.tabItem(index, item))})}

至于右侧的按钮布局,其实和自定义tabBar一致,采用的是RelativeContainer组件,包裹住按钮组件和tabBar组件即可,当然了,更多的代码,大家还是查看源码比较好,代码里的注释写的比较详细。

三、开源地址

地址中也有详细的使用概述:

https://ohpm.openharmony.cn/#/cn/detail/@abner%2Ftab

四、相关总结

指示器随着手势滑动,系统中的Api是支持的,但是需要实现的代码量很多,而且模式只支持Fixed,那么在导航条目较多的情况下,这个模式是很不符合需求的,当然了,我也在一步一步优化中,也希望在较短的时间内可以实现,大家可以持续关注。

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

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

相关文章

GRAF: Generative Radiance Fields for 3D-Aware Image Synthesis

GRAF: Generative Radiance Fieldsfor 3D-Aware Image Synthesis&#xff08;基于产生辐射场的三维图像合成&#xff09; 思维导图&#xff1a;https://blog.csdn.net/weixin_53765004/article/details/137944206?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3…

THREEJS 使用CatmullRomCurve3实现汽车模型沿着指定轨迹移动

效果预览 准备所需资源 搭建场景环境 const container document.querySelector("#box_bim");// 创建摄像机camera new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,0.1,1000);// camera.position.set(500, 500, 500);// 调整近裁减值camer…

java基础教程(2)-Java基本数据类型

一个Java程序的基本结构&#xff1a; public class DemoTest {public static void main(String[] args) {// 打印一句话System.out.println("hello...");} }以上程序功能是实现打印一句话到控制台输出&#xff1b;这是一个基本的java结构&#xff0c;所有java程序都…

【数据结构】 单向链表的实现

单向链表是数据结构中的一种&#xff0c;它由节点组成&#xff0c;每个节点包含两个部分&#xff1a;数据域和指针域。数据域用于存储节点的值&#xff0c;指针域则用于指向下一个节点。单向链表的特点是只能从头节点开始遍历到尾节点&#xff0c;不能反向遍历。 1 单向链表的…

深入剖析图像平滑与噪声滤波

噪声 在数字图像处理中&#xff0c;噪声是指在图像中引入的不希望的随机或无意义的信号。它是由于图像采集、传输、存储或处理过程中的各种因素引起的。 噪声会导致图像质量下降&#xff0c;使图像失真或降低细节的清晰度。它通常表现为图像中随机分布的亮度或颜色变化&#…

面试不慌张:一文读懂FactoryBean的实现原理

大家好&#xff0c;我是石头~ 在深入探讨Spring框架内部机制时&#xff0c;FactoryBean无疑是一个关键角色&#xff0c;也是面试中经常出现的熟悉面孔。 不同于普通Java Bean&#xff0c;FactoryBean是一种特殊的Bean类型&#xff0c;它的存在并非为了提供业务逻辑&#xff0c;…

docker-002常用命令

启动类命令 启动systemctl start docker停止systemctl stop docker重启systemctl restart docker查看状态systemctl status docker开机启动systemctl enable docker概要docker info总体帮助文档docker --help命令帮助文档docker 具体命令 --help镜像命令 查看主机上的镜像 命令…

基于Springboot的小区物业管理系统

基于SpringbootVue的小区物业管理系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 用户管理 员工管理 业主信息管理 费用信息管理 楼房信息管理 保修信息…

【原创教程】海为PLC与RS-WS-ETH-6传感器的MUDBUS_TCP通讯

一、关于RS-WS-ETH-6传感器的准备工作 要完成MODBUS_TCP通讯,我们必须要知道设备的IP地址如何分配,只有PLC和设备的IP在同一网段上,才能建立通讯。然后还要选择TCP的工作模式,来建立设备端和PC端的端口号。接下来了解设备的报文格式,方便之后发送报文完成数据交互。 1、…

自定义Blazor单文件Web程序端口

#接 上篇 Mysql快速迁移版的制作过程# 上一篇《Mysql8快速迁移版的制作过程》完成了快速迁移的数据库的准备&#xff0c;今天接着讲基于Blazor的Web程序快速迁移版的制作。 单文件发布的难点不在发布而是因为程序系统默认给了个5001的端口&#xff0c;而是如何能够让用户自定…

AOP基础-动态代理

文章目录 1.动态代理1.需求分析2.动态代理的核心3.代码实例1.Vehicle.java2.Car.java3.Ship.java4.VehicleProxyProvider.java(动态代理模板)5.测试使用 2.动态代理深入—横切关注点1.需求分析2.四个横切关注点3.代码实例1.Cal.java2.CalImpl.java3.VehicleProxyProvider02.jav…

0-1背包问题:贪心算法与动态规划的比较

0-1背包问题&#xff1a;贪心算法与动态规划的比较 1. 问题描述2. 贪心算法2.1 贪心策略2.2 伪代码 3. 动态规划3.1 动态规划策略3.2 伪代码 4. C语言实现5. 算法分析6. 结论7. 参考文献 1. 问题描述 0-1背包问题是组合优化中的一个经典问题。假设有一个小偷在抢劫时发现了n个…

CSS继承、层叠和特殊性

继承性 CSS样式的相互传递&#xff0c;也就是说CSS内部标签拥有CSS外部标签的某些样式。我们可以利用CSS的继承性先把网页中具有相同&#xff0c;可继承的样式提取出来&#xff0c;然后进行全局中定义&#xff0c;利用继承属性影响整个页面的样式。 CSS中不可以继承的属性 1…

(C语言)sscanf 与 sprintf详解

目录 1.sprintf函数详解 2. sscanf函数详解 1.sprintf函数详解 头文件&#xff1a;stdio.h 作用&#xff1a;将格式化的数据写入字符串里&#xff0c;也就是将格式化的数据转变为字符串。 演示&#xff1a; #include <stdio.h> struct S {char name[10];int height;…

L1-039 古风排版--Python

中国的古人写文字&#xff0c;是从右向左竖向排版的。本题就请你编写程序&#xff0c;把一段文字按古风排版。 输入格式&#xff1a; 输入在第一行给出一个正整数N&#xff08;<100&#xff09;&#xff0c;是每一列的字符数。第二行给出一个长度不超过1000的非空字符串&a…

【QT进阶】Qt http编程之http与https简单介绍

往期回顾 【QT进阶】Qt Web混合编程之html、 js的简单交互-CSDN博客 【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等-CSDN博客【QT进阶】Qt Web混合编程之实现ECharts数据交互动态修改-CSDN博客 【QT进阶】Qt http编程之http与https简单介绍 一、什么是http与https …

NX二次开发——矩形排料5(基于最低水平线+遗传算法排料策略实现)

目录 一、概述 二、知识回顾 2.1适应度函数的确定 2.2基因编码 2.3遗传算法复制&#xff08;选择&#xff09; 2.4遗传算法交叉操作 通过交叉操作可以增加种群个体的多样性&#xff0c;既可以产生更多的优秀解。下面通过顺序编码方法进行改进&#xff08;网上有很…

ThreadLocal 实战使用详解

ThreadLocal 知识储备传送门&#xff1a; ThreadLocal 原理及源码详解 ThreadLocal 内存泄漏和常见问题详解 什么是ThreadLocal&#xff1f; ThreadLocal 是一种提供线程本地变量&#xff08;也称为线程局部变量&#xff09;的类&#xff0c;这种变量确保了在不同的线程中访…

vue3:树的默认勾选和全选、取消全选

实现的功能&#xff0c;上面有个选择框&#xff0c;当选中全部时&#xff0c;下方树被全选 代码&#xff1a; <template><div><el-select v-model"selectAll" style"margin-bottom: 10px;" change"handleSelectAllChange">&…

electron打包dist为可执行程序后记【electron-quick-start】

文章目录 目录 文章目录 前言 一、直接看效果 二、实现步骤 1.准备dist文件夹 2.NVM管理node版本 3.准备electron容器并npm run start 4.封装成可执行程序 1.手动下载electron对应版本的zip文件&#xff0c;解决打包缓慢问题 2.安装packager 3.配置打包命令执行内容…