您现在的位置是:首页 > 编程 > 

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

2025-07-27 19:48:14
HarmonyOs开发:导航tabs组件封装与使用 前言本文基于Api12主页的底部导航以及页面顶部的切换导航,无论哪个系统,哪个App,都是最常见的功能之一,虽然说在鸿蒙中有现成的组件tabs可以很快速的实现,但是在使用的时候,依然有几个潜在的问题存在,第一,当导航较少时,tabs是默认居中模式,目前无法进行居左,在有这样功能的时候,难以满足需求;第二,导航右侧需要展示按钮的时候,tabs也是无

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

前言

本文基于Api12

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

本篇的文章内容如下:

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

2、主要的封装实现分析

、开源地址

4、相关总结

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

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

(功能项)

(底部Tab)

(普通导航)

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

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

代码语言:typescript复制
ohpm install @abner/tab

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

代码语言:typescript复制
"dependencies": { "@abner/tab": "^1.0.4"}

1、底部导航案例

相关效果:

代码实现:
代码语言:typescript复制
@Entry
@Component
struct BottomTabPage1 {
  /**
   * AUTHOR:AbnerMing
   * ITRODUCE:tab对应的页面
   * @param index 索引
   * @param item TabBar对象,非必须
   * */
  @Builder
  itemPage(index: number, item: TabBar) {
    Text()
  }

build() {
    Column() {
      ActionBar({ title: "底部导航案例一" })

      BottomTabLayout({
        itemPage: this.itemPage,//tab对应的页面
        tabSelectedColor: "#D81E06",//文字未选择颜
        tabormalColor: Color.Black,//文字未选择颜
        tabLabelMarginTop: 10,//文字距离图片的高度
        tabScrollable: true,//是否可以滑动
        tabMarginBottom: 0, //距离底部的距离,一般可以获取底部导航栏的高度,然后进行设置
        onChangePage: (position) => {
          //页面切换
        },
        onTabBarClick: (position) => {
          //tab点击
        },
        tabBar: [
          new TabBar("首页", $r("ic_home_select"), $r("ic_home_unselect")),
          new TabBar("网络", $r("ic_net_select"), $r("ic_net_unselect")),
          new TabBar("列表", $r("ic_list_select"), $r("ic_list_unselect")),
          new TabBar("组件", $r("ic_view_select"), $r("ic_view_unselect"))
        ]
      })
    }.height("100%")
}
}
相关属性

属性

类型

概述

itemPage

BuilderParam

tab对应得页面

tabSelectedColor

ResourceColor

tab选中颜

tabormalColor

ResourceColor

tab未选中颜

tabSelectedBgColor

ResourceColor

选中背景颜

tabormalBgColor

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视图

相关效果:

代码实现:
代码语言:typescript复制
@Entry
@Component
struct BottomTabPage2 {
  private currentIndex = 0 //默认是第一个

  /**
   * AUTHOR:AbnerMing
   * ITRODUCE:tab对应的页面
   * @param index 索引
   * @param item TabBar对象,非必须
   * */
  @Builder
  itemPage(index: number, item: TabBar) {
    Text()
  }

/**
 * AUTHOR:AbnerMing
 * ITRODUCE:自定义Tab视图,自己绘制
 * @param index 索引
 * @param item TabBar对象,非必须
 * */
@Builder
itemTab(index: number, item: TabBar) {
    Column() {
      Image( == index ? item.selectedIcon
        : )
        .width(0).height(0)
      Text()
        .fontColor( == 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("ic_home_select"), $r("ic_home_unselect")),
          new TabBar("网络", $r("ic_net_select"), $r("ic_net_unselect")),
          new TabBar("列表", $r("ic_list_select"), $r("ic_list_unselect")),
          new TabBar("组件", $r("ic_view_select"), $r("ic_view_unselect"))
        ],
        tabMarginBottom: 0, //距离底部的距离,一般可以获取底部导航栏的高度,然后进行设置
        onTabBarClick: (position) => {
          //tab点击
          cole.log("====点击了Tab" + position)
        },
        onChangePage: (position) => {
          //页面切换
          cole.log("====页面切换了" + position)
        }
      })
    }
}
}
相关属性

属性

类型

概述

itemPage

BuilderParam

tab对应得页面

tabSelectedColor

ResourceColor

tab选中颜

tabormalColor

ResourceColor

tab未选中颜

tabSelectedBgColor

ResourceColor

选中背景颜

tabormalBgColor

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距离底部的距离

、底部导航案例,中间图片

代码案例
代码语言:typescript复制
/**
 * AUTHOR:AbnerMing
 * DATE:2024//5
 * ITRODUCE:底部导航案例中间图片
 * */
@Entry
@Component
struct BottomTabPage4 {
  private currentIndex = 0 //默认是第一个

  /**
   * AUTHOR:AbnerMing
   * ITRODUCE:tab对应的页面
   * @param index 索引
   * @param item TabBar对象,非必须
   * */
  @Builder
  itemPage(index: number, item: TabBar) {
    Text()
  }

  /**
   * AUTHOR:AbnerMing
   * ITRODUCE:自定义Tab视图,自己绘制
   * @param index 索引
   * @param item TabBar对象,非必须
   * */
  @Builder
  itemTab(index: number, item: TabBar) {
    if (index == 2) {
      Column() {
        Image($r("add"))
          .width(50).height(50)
          .margin({ top: -10 })
      }
    } else {
      Column() {
        Column() {
          Image( == index ? item.selectedIcon
            : )
            .width(0).height(0)
          Text()
            .fontColor( == index ? "#D81E06" : "#000000")
            .fontSize(14)
            .margin({ top: 5 })
        }
      }.width("100%")
      .justifyContent(FlexAlign.Center)
    }
  }

  build() {
    Column() {
      ActionBar({ title: "自定义底部导航(中间图片)" })
      BaseBottomTabLayout({
        itemPage: this.itemPage,
        itemTab: this.itemTab,
        barBackgroundColor: "#e8e8e8",
        centerImageMarginBottom: 10,
        tabBar: [
          new TabBar("首页", $r("ic_home_select"), $r("ic_home_unselect")),
          new TabBar("网络", $r("ic_net_select"), $r("ic_net_unselect")),
          new TabBar("中间图片"),
          new TabBar("列表", $r("ic_list_select"), $r("ic_list_unselect")),
          new TabBar("组件", $r("ic_view_select"), $r("ic_view_unselect"))
        ],
        tabMarginBottom: 0, //距离底部的距离,一般可以获取底部导航栏的高度,然后进行设置
        onTabBarClick: (position) => {
          //tab点击
          cole.log("====点击了Tab" + position)
        },
        onChangePage: (position) => {
          //页面切换
          cole.log("====页面切换了" + position)
        },
        onDoubleClick: (position) => {
          //双击
          cole.log("===========双击:" + position)
        },
      })
    }
  }
}

4、普通指示器导航【滑动】

简单案例
代码语言:typescript复制
TabLayout({
  tabBar: ["条目一", "条目二"],
  itemPage: this.itemPage,
  onChangePage: (position) => {
    //页面改变
    cole.log("===页面改变:" + position)
  },
  onTabBarClick: (position) => {
    //点击改变
    cole.log("===点击改变:" + position)
  }
})
设置圆角
代码语言:typescript复制
TabLayout({
            tabBar: ["条目一", "条目二", "条目三", "条目四", "条目五", "条目六"],
            itemPage: this.itemPage,
            tabAttribute: (tab) => {
               = 10
               = LineCapStyle.Round
            },
            onChangePage: (position) => {
              //页面改变
              cole.log("===页面改变:" + position)
            },
            onTabBarClick: (position) => {
              //点击改变
              cole.log("===点击改变:" + position)
            }
          })
设置宽度
代码语言:typescript复制
TabLayout({
            tabBar: ["条目一", "条目二", "条目三", "条目四", "条目五", "条目六"],
            itemPage: this.itemPage,
            tabAttribute: (tab) => {
               = 20
            },
            onChangePage: (position) => {
              //页面改变
              cole.log("===页面改变:" + position)
            },
            onTabBarClick: (position) => {
              //点击改变
              cole.log("===点击改变:" + position)
            }
          })
跟随文字宽度
代码语言:typescript复制
TabLayout({
            tabBar: ["一", "第二", "条目三", "是条目四", "我是条目五", "最后是条目六"],
            itemPage: this.itemPage,
            tabAttribute: (tab) => {
               = undefined
               = { left: 10, right: 10 }
              //更改下划线的宽度
               = undefined
            },
            onChangePage: (position) => {
              //页面改变
              cole.log("===页面改变:" + position)
            },
            onTabBarClick: (position) => {
              //点击改变
              cole.log("===点击改变:" + position)
            }
          })
左侧按钮
代码语言:typescript复制
TabLayout({
            tabBar: ["条目一", "条目二", "条目三", "条目四", "条目五", "条目六"],
            itemPage: this.itemPage,
            tabMenu: this.itemMenu, //按钮
            onChangePage: (position) => {
              //页面改变
              cole.log("===页面改变:" + position)
            },
            onTabBarClick: (position) => {
              //点击改变
              cole.log("===点击改变:" + position)
            }
          })
自定义下划线
代码语言:typescript复制
BaseTabLayout({
            tabBar: ["条目一", "条目二", "条目三", "条目四", "条目五", "条目六"],
            itemPage: this.itemPage,
            tabModel: {
              tabDividerStrokeWidth: 15
            },
            itemTabIndicator: () => {
              (this) //自己定义指示器
            },
            itemTab: (index: number, item: string) => {
              (this, index, item)
            },
          })
相关属性

属性

类型

概述

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按钮距离右侧的距离

5、普通指示器导航【不可滑动】

简单案例
代码语言:typescript复制
TabLayout({
        tabBar: ["条目一", "条目二", "条目三", "条目四", "条目五", "条目六"],
        itemPage: this.itemPage,
        tabType: TabType.DEFAULT, //普通的需要设置默认值,指示器不会跟着手势滑动
        onChangePage: (position) => {
          //页面改变
          cole.log("===页面改变:" + position)
        },
        onTabBarClick: (position) => {
          //点击改变
          cole.log("===点击改变:" + position)
        }
      })
均分
代码语言:typescript复制
TabLayout({
        tabBar: ["条目一", "条目二"],
        barMode: BarMode.Fixed, //均分
        tabType: TabType.DEFAULT, //普通的需要设置默认值,指示器不会跟着手势滑动
        itemPage: this.itemPage,
        onChangePage: (position) => {
          //页面改变
          cole.log("===页面改变:" + position)
        },
        onTabBarClick: (position) => {
          //点击改变
          cole.log("===点击改变:" + position)
        }
      })
二、主要的封装实现分析

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

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

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

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

代码语言:typescript复制
//使用tabBar对象形式传递
        if (this.isTabAlignLeft) {
          ForEach(, (item: string, index) => {
            TabContent() {
              this.itemPage(index, item)
            }
          })
        } else {
          ForEach(, (item: string, index) => {
            TabContent() {
              this.itemPage(index, item)
            }.tabBar((index, item))
          })
        }

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

三、开源地址

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

/@abner%2Ftab

四、相关总结

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

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1232292.html

相关标签:无
上传时间: 2025-07-26 09:34:01
留言与评论(共有 18 条评论)
本站网友 trumpf
8分钟前 发表
this.scroller }) { ForEach(
本站网友 西单大悦城地址
15分钟前 发表
(tab) => { = 10 = LineCapStyle.Round }
本站网友 永州租房信息
16分钟前 发表
item
本站网友 打印服务
29分钟前 发表
number
本站网友 zfs
15分钟前 发表
})相关属性属性类型概述tabWidthLengthtab指示器的宽度tabHeightnumbertab指示器的高度onChangePage回调方法(position
本站网友 kaqi
10分钟前 发表
item) }.tabBar((index
本站网友 精密铸造件
4分钟前 发表
itemTabIndicator
本站网友 西安市高新一小
13分钟前 发表
(item
本站网友 复仇者刷图厉害吗
4分钟前 发表
onTabBarClick
本站网友 广东爱情故事
28分钟前 发表
大家可以按照以下的方式进行使用
本站网友 清水河二手房
26分钟前 发表
大家还是查看源码比较好
本站网友 播客网
21分钟前 发表
10 } //更改下划线的宽度 = undefined }
本站网友 意见书格式
18分钟前 发表
默认滑动onTabBarClick回调方法(position
本站网友 英雄志23
0秒前 发表
itemPage
本站网友 smt是什么
28分钟前 发表
"底部导航案例一" }) BottomTabLayout({ itemPage
本站网友 星耀五洲破产
0秒前 发表
$r("ic_view_select")
本站网友 天津mba辅导
23分钟前 发表
true