logo
积分中心
【HarmonyOS 7 悬浮页签深度实战】01 HdsTabs、Tabs 与悬浮页签如何选择 原创
头像 小雨同学 2026-09-09 10:52:35    发布
4791 浏览 29 点赞 0 收藏

前言

现有 HarmonyOS 项目已经有底部导航时,准备改成悬浮页签,最先遇到的问题通常发生在接口选择这里。

项目里原来可能使用 Tabs,页面切换、选中状态和业务数据都已经稳定。开始接触悬浮导航以后,又会碰到 HdsTabs、HdsTabsController、BottomTabBarStyle 和 barFloatingStyle。几个名称放到一起以后,很容易把它们理解成几套可以互相替换的页签组件。

实际关系要简单一些。

Tabs 属于 ArkUI,用来组织多个 TabContent 并完成页签内容切换。HdsTabs 位于 UI Design Kit,UI Design Kit 本身是符合 HarmonyOS Design System 的界面开发套件集合;HdsTabs 已经在 6.0.0(20) Beta1 的 UI Design Kit API 中出现。

悬浮页签继续使用 HdsTabs。页面需要同时设置底部页签、横向排列、内容与页签叠加,再通过 barFloatingStyle 配置悬浮区域。当前悬浮页签的基本条件可以归纳为 barPosition=BarPosition.End、vertical=false、barOverlap=true 和 barFloatingStyle。

所以,已有项目准备改底部导航时,可以先回答两个问题。

当前页面只需要普通页签切换,还是已经准备使用悬浮导航?悬浮导航后面是否还会继续处理 MiniBar、握姿跟随或者不同窗口宽度?

这两个问题确认以后,Tabs 和 HdsTabs 的选择会清楚很多。

目前我的测试环境仍然以 HarmonyOS 7 模拟器为主。基础组件、页签切换和悬浮布局可以先在模拟器中检查;左右手握姿、真实折叠状态以及最终操作手感仍然需要支持相关能力的真机。

一、先把 Tabs、HdsTabs 和悬浮页签分清楚

已有项目最容易混淆的地方,是把三者都理解成底部导航。它们所在的层级其实不同。

Tabs 负责常规页签切换

Tabs 是 ArkUI 中的页签容器,内部通过多个 TabContent 承载不同内容。barPosition 可以决定页签栏的位置,TabContent 则负责每一个页签对应的页面内容。

一个普通的底部导航可以写成:

Tabs({  barPosition: BarPosition.End}) {  TabContent() {    Text('首页内容')  }  .tabBar('首页')​  TabContent() {    Text('任务内容')  }  .tabBar('任务')​  TabContent() {    Text('我的内容')  }  .tabBar('我的')}

这种结构已经能够覆盖大量业务页面。

例如首页、任务、个人中心三个一级入口,只需要固定底栏和内容切换,现有 Tabs 已经运行稳定,项目可以继续保持原来的导航结构。

此时没有必要因为悬浮页签出现,就先修改整个导航容器。真正需要重新判断的时候,是需求开始进入 HDS 页签范围。

HdsTabs 属于 UI Design Kit

HdsTabs 位于 UI Design Kit。它依然使用 TabContent 承载页面,因此已有业务内容通常可以继续保留。改变的主要是外层页签容器,以及 HDS 提供的页签能力。

基础结构可以写成:

import {  HdsTabs,  HdsTabsController} from '@kit.UIDesignKit';​private controller: HdsTabsController =  new HdsTabsController();​HdsTabs({  controller: this.controller}) {  TabContent() {    Text('首页内容')  }  .tabBar('首页')​  TabContent() {    Text('任务内容')  }  .tabBar('任务')​  TabContent() {    Text('我的内容')  }  .tabBar('我的')}.barPosition(BarPosition.End).vertical(false)

这里有一个对已有项目很友好的地方。

原来的首页、任务页、个人中心仍然可以放在 TabContent 里。迁移时可以先处理导航容器,业务页面暂时保持原状。

这样出现问题时,排查范围主要集中在页签结构,不会同时把业务状态、接口请求和页面布局全部卷进来。

悬浮页签是 HdsTabs 的悬浮形态

大家很容易继续寻找一个单独的悬浮页签组件。

当前悬浮形态依然建立在 HdsTabs 上。页面需要把页签放到底部、保持横向排列,让 TabBar 覆盖到 TabContent 上,再配置 barFloatingStyle。

调用关系可以整理成:

HdsTabs↓barPosition = BarPosition.End↓vertical = false↓barOverlap = true↓barFloatingStyle(...)↓底部悬浮页签

所以项目里的几个对象可以这样区分:


对象主要职责
TabsArkUI 常规页签与内容切换
HdsTabsHDS 页签容器
TabContent每个页签对应的业务内容
BottomTabBarStyle底部页签的图标、文字等样式
HdsTabsController页签相关控制
barFloatingStyle悬浮页签区域配置
悬浮页签HdsTabs 进入悬浮布局后的页面形态

BottomTabBarStyle 也需要单独理解。

它负责底部页签的视觉内容,和整个 HdsTabs 容器并不是同一个对象。HarmonyOS 的底部页签设计本身就包含图标、文本、选中状态等内容表达。

因此,整个结构更适合按照下面的层次去理解:

业务内容TabContent​页签容器Tabs / HdsTabs​底部页签样式BottomTabBarStyle​悬浮布局barFloatingStyle​页签控制HdsTabsController

把这些层次分开以后,后面看到 MiniBar、页签显隐或者握姿跟随时,就知道应该继续检查哪一层接口。

三者的关系清楚以后,接口选择就可以回到已有项目本身。

二、现有项目怎么判断要不要换成 HdsTabs

页面选择 Tabs 还是 HdsTabs,没有必要只看底栏视觉效果。更实用的判断方式,是把当前需求和接下来准备增加的能力列出来。

普通底部导航可以继续使用 Tabs

假设一个工具应用已经有四个一级页面:

首页收藏历史设置

业务只要求固定底栏、页面切换和选中状态,底栏样式也已经由项目自己维护。这种情况下,Tabs 已经能够承担当前任务。

保留现有组件可以减少改动范围,也不会因为导航改造去碰已经稳定的页面逻辑。

准备使用悬浮导航时,再进入 HdsTabs

当页面开始需要胶囊形悬浮导航,或者内容要延伸到底部导航后方时,HdsTabs 就进入了选择范围。

悬浮形态下,barOverlap=true 会让 TabBar 与 TabContent 形成叠加关系,因此内容区和底部导航之间的空间处理也会跟普通固定底栏不同。

项目可以先按照需求做一轮判断:


当前需求可以优先考虑
普通顶部或底部页签Tabs
HDS 页签结构HdsTabs
底部悬浮导航HdsTabs + barFloatingStyle
内容延伸到页签后方HdsTabs + barOverlap
MiniBarHDS 悬浮页签
左右手握姿适配HDS 悬浮页签
宽窗口继续调整悬浮导航HDS 页签结构

这里比较容易误判的是,把 HdsTabs 当成一个必须替换 Tabs 的新版本。

项目是否迁移,还是要看现有页面准备使用哪些能力。

如果普通页签已经满足需求,继续维护 Tabs 会更省事。如果页面已经确定要做悬浮导航,并且后面还会增加 MiniBar、握姿跟随或者多窗口处理,那么从 HdsTabs 开始搭结构会更合适。

智感握姿也建立在悬浮 HdsTabs 上

握姿适配可以进一步帮助判断 HdsTabs 的使用边界。

HdsTabs 进入悬浮状态以后,barFloatingStyle 中可以通过 adaptToHandedness 让底部页签栏跟随握持手变化。这个能力要求页签已经处于 barOverlap 开启的悬浮状态。

所以,当产品设计里已经出现单手操作、左右手热区或者悬浮导航跟随需求时,页面从一开始就需要考虑 HdsTabs 的悬浮结构。

当前模拟器可以先检查属性和布局,真实握姿变化仍然要留到支持对应能力的设备上。

HdsTabsController 负责控制问题

另外一个容易和样式混在一起的对象是 HdsTabsController。HdsTabsOptions 提供 controller?: HdsTabsController,因此控制器属于 HdsTabs 的控制入口。

把结构继续拆开以后,可以形成下面这组关系:

页面放什么→ TabContent​用哪一种页签容器→ Tabs / HdsTabs​底部页签长什么样→ BottomTabBarStyle​页签是否悬浮→ barFloatingStyle​页签如何被控制→ HdsTabsController

这套分法在后面处理显隐、主动切换和业务状态时会很有用。

同一个问题只交给一层处理,代码也更容易维护。

三、先跑通基础 HdsTabs 再增加悬浮配置

接口选择最终还是要回到工程里验证。

当前环境已经准备好 UI Design Kit 时,可以先搭一个只有三个页签的 HdsTabs 页面。页面不加入 MiniBar、握姿或者复杂材质,只确认容器、TabContent 和底部页签能够正常工作。

先确认 UIDesignKit 能够正常导入

核心导入只有:

import {  HdsTabs,  HdsTabsController} from '@kit.UIDesignKit';

HdsTabs 已经在 6.0.0(20) Beta1 的 UI Design Kit API 中出现,因此使用 HarmonyOS 7 环境时,要避免把 HdsTabs 本身误判为 HarmonyOS 7 才提供的组件。

页面随后创建控制器:

private controller: HdsTabsController =  new HdsTabsController();

再准备三个 TabContent:

HdsTabs({  controller: this.controller}) {  TabContent() {    this.tabPage(      '首页',      '当前页面用于检查 HdsTabs 的基础切换。'    )  }  .tabBar('首页')  TabContent() {    this.tabPage(      '任务',      '业务内容继续由 TabContent 承载。'    )  }  .tabBar('任务')  TabContent() {    this.tabPage(      '我的',      '页签容器变化不会要求业务内容重写。'    )  }  .tabBar('我的')}.barPosition(BarPosition.End).vertical(false)

运行以后,先确认三个结果:

HdsTabs 正常创建TabContent 正常显示三个页签可以正常切换

这三个条件成立以后,基础 HDS 页签链路就已经可用。

悬浮配置适合分步加入

基础页面已经能够正常切换以后,再增加:

.barOverlap(true)

随后加入:

.barFloatingStyle({  // 悬浮页签配置})

悬浮页签本身要求 barPosition=BarPosition.End、vertical=false、barOverlap=true,并配置 barFloatingStyle。

分步增加有一个很现实的好处。

页签突然不符合预期时,可以知道问题发生在普通 HdsTabs,还是发生在悬浮布局配置。

如果从第一版代码就同时加入 MiniBar、材质、渐变遮罩和握姿适配,任何一个字段出错都会扩大排查范围。

只确认当前环境已经走通基础调用

模拟器中的这张页面能够帮助确认基础工程链路。

如果 @kit.UIDesignKit 无法导入,问题需要回到 SDK 和工程环境。如果 HdsTabs 已经创建,但页面结构异常,可以继续检查容器和 TabContent。基础结构稳定以后,再进入 barOverlap 和 barFloatingStyle。

总结

现有项目遇到 Tabs、HdsTabs 和悬浮页签时,可以先把它们放到不同层级。

Tabs 负责 ArkUI 常规页签。HdsTabs 属于 UI Design Kit,业务内容仍然通过 TabContent 承载。悬浮页签继续使用 HdsTabs,通过 barPosition、vertical、barOverlap 和 barFloatingStyle 调整成悬浮布局。

项目选择时也可以保持一个比较简单的判断。

普通底栏已经满足需求,现有 Tabs 可以继续维护。页面准备使用 HDS 悬浮导航、MiniBar、智感握姿或者继续处理宽窗口布局时,再评估 HdsTabs。

已有业务页面通常不用跟着导航容器一起重写。首页、任务页、个人中心仍然可以留在 TabContent 中,先完成外层容器验证,再增加悬浮布局。

当前模拟器能够承担 HdsTabs 基础调用、页面切换和悬浮结构的验证。智感握姿、真实折叠状态、最终交互距离和设备性能仍然需要对应真机环境。

完整代码

Main.ets

/** * HarmonyOS 7 悬浮页签深度实战 01 * */​import {  HdsTabs,  HdsTabsController} from '@kit.UIDesignKit';​@Entry@Componentstruct Main {  /**   * HdsTabs 的控制对象。   * 页签状态控制可以继续复用这个对象。   */  private controller: HdsTabsController =    new HdsTabsController();​  @Builder  private tabPage(    title: string,    description: string,    label: string  ) {    Column({ space: 18 }) {      Column({ space: 6 }) {        Text('HarmonyOS 7 悬浮页签')          .fontSize(28)          .fontWeight(FontWeight.Bold)          .fontColor('#11182C')          .width('100%')​        Text('HdsTabs 基础模式')          .fontSize(16)          .fontColor('#68708A')          .width('100%')      }      .width('100%')      .alignItems(HorizontalAlign.Start)​      Column({ space: 8 }) {        Text('当前检查')          .fontSize(14)          .fontWeight(FontWeight.Medium)          .fontColor('#5065E8')          .width('100%')​        Text(          '当前页面检查 HdsTabs、'            + 'TabContent 和底部页签的基础调用。'        )          .fontSize(13)          .fontColor('#68708A')          .lineHeight(20)          .width('100%')​        Text(          '基础页面保持普通底栏,'            + '方便观察容器和页面切换是否正常。'        )          .fontSize(13)          .fontColor('#68708A')          .lineHeight(20)          .width('100%')      }      .width('100%')      .padding(16)      .backgroundColor(Color.White)      .borderRadius(20)      .alignItems(HorizontalAlign.Start)​      Column({ space: 10 }) {        Text(label)          .fontSize(12)          .fontWeight(FontWeight.Medium)          .fontColor('#5065E8')          .width('100%')​        Text(title)          .fontSize(24)          .fontWeight(FontWeight.Bold)          .fontColor('#17203A')          .width('100%')​        Text(description)          .fontSize(14)          .fontColor('#68708A')          .lineHeight(22)          .width('100%')      }      .width('100%')      .layoutWeight(1)      .padding(20)      .justifyContent(FlexAlign.Center)      .alignItems(HorizontalAlign.Start)      .backgroundColor('#F8F9FD')      .borderRadius(24)​      Column({ space: 6 }) {        Text('当前接口关系')          .fontSize(14)          .fontWeight(FontWeight.Medium)          .fontColor('#17203A')          .width('100%')​        Text(          'HdsTabs → TabContent → tabBar'        )          .fontSize(13)          .fontColor('#68708A')          .width('100%')​        Text(          '进入悬浮布局时,'            + '还需要配置 barOverlap 和 barFloatingStyle。'        )          .fontSize(12)          .fontColor('#747C92')          .lineHeight(18)          .width('100%')      }      .width('100%')      .padding(16)      .backgroundColor(Color.White)      .borderRadius(20)      .alignItems(HorizontalAlign.Start)    }    .width('100%')    .height('100%')    .padding({      left: 20,      right: 20,      top: 24,      bottom: 18    })    .backgroundColor('#F4F6FB')  }​  build() {    /**     * @Entry 的根节点使用 Column。     * HdsTabs 放在根容器内部,     * 避免直接把 HdsTabs 作为 Entry 根节点。     */    Column() {      HdsTabs({        controller: this.controller      }) {        TabContent() {          this.tabPage(            '首页',            '基础页面已经放进 HdsTabs,'              + '当前可以检查内容和底部页签切换。',            'TAB 01'          )        }        .tabBar('首页')​        TabContent() {          this.tabPage(            '任务',            '业务内容继续由 TabContent 承载,'              + '页面状态可以保持原来的组织方式。',            'TAB 02'          )        }        .tabBar('任务')​        TabContent() {          this.tabPage(            '我的',            '外层使用 HdsTabs 后,'              + '业务页面仍然可以保持独立。',            'TAB 03'          )        }        .tabBar('我的')      }      .barPosition(BarPosition.End)      .vertical(false)      .width('100%')      .layoutWeight(1)    }    .width('100%')    .height('100%')  }}


©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS

暂无评论数据

加载中...

发布

头像

小雨同学

产品总监、独立开发者社群主理人、资深全栈工程师,HarmonyOS应用开发者高级认证,PMP认证,CSDN博客专家,鸿蒙极客,Trae Fellow,阿里云社区专家博主、51CTO 博客专家、OpenTiny 优秀布道师、科大讯飞荣誉讲师。

53

帖子

0

提问

145

粉丝

关注
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255