【HarmonyOS 7 悬浮页签深度实战】08 现有 Tabs 迁移、问题排查与降级策略
文章目录
前言
一个已经运行了一段时间的 HarmonyOS 项目,底部 Tabs 通常早就超出了页面切换的范围。当前索引、列表筛选、表单草稿、播放进度、路由入口和埋点,都可能围绕这组导航组织起来。
此时准备接入 HdsTabs,工作量经常会被低估。
代码里把 Tabs 替换成 HdsTabs 并不复杂,真正麻烦的是迁移过程中同时修改了导航容器、控制器、悬浮布局和业务页面。页面出现状态丢失、底部遮挡或者重复请求以后,很难马上确认问题来自哪一层。
假设用户已经进入任务页,填写了一半表单。页面切换成悬浮 HdsTabs 后,任务页突然回到首页,表单内容也恢复了初始值。这个现象表面上发生在导航切换时,原因却可能分布在多个位置。当前索引可能保存在旧的 TabsController 里,表单状态可能位于即将销毁的 TabContent 中,悬浮栏又可能覆盖了底部操作按钮。
我处理这类迁移时,通常会先保留一份能够正常运行的 ArkUI Tabs,再把业务状态移动到导航容器之外。随后依次验证普通 HdsTabs、悬浮 HdsTabs 和其他可选能力。每次只改变一层,出现异常时也能够退回上一种已经确认的状态。
这种处理方式看起来多了几次比较,后面反而会省下不少排查时间。尤其是已经上线的项目,导航调整不应该牵着业务页面一起重新编写。
HdsTabs 的子组件仍然是 TabContent,HdsTabsOptions 继承自 TabsOptions。现有业务页面具备继续复用的基础,真正需要替换的是外层容器和控制器。HdsTabsController 继承自 TabsController,但一个控制器不能同时管理多个 HdsTabs,因此普通模式和悬浮模式需要分别准备控制器。
我目前手里还没有可以测试 HarmonyOS 7 的真机,所以现在主要通过 HarmonyOS 7 模拟器检查导航切换、状态保存和页面布局。系统能力、设备差异以及最终交互体验,仍然要以真机实际运行结果为准。

一、先把业务状态稳定
现有项目里的 Tabs 往往同时管理两类内容。一类属于导航,例如当前选中的页签索引、主动跳转和滑动切换。另一类属于业务,例如表单草稿、筛选条件、未完成任务、播放进度和操作次数。
两类状态混在同一个组件内部时,导航容器被替换,业务数据也容易跟着重新初始化。
这也是为什么迁移以前要先保留一份基线。这里的基线不能只有一张页面截图,它需要真实记录当前导航如何工作,用户操作以后哪些状态会变化,窗口调整以后页面是否仍然可用。
可以先整理下面几类内容。
| 需要保留的内容 | 迁移前需要确认什么 |
|---|---|
| 导航状态 | 启动页签、点击切换、滑动切换、业务按钮跳转、返回页面后的选中项 |
| 业务状态 | 表单草稿、列表筛选、任务进度、播放状态、操作计数 |
| 页面布局 | 底部安全区、最后一个列表项、固定按钮、横竖屏、分屏与自由窗口 |
| 工程环境 | 当前 SDK、目标设备、构建配置以及能够正常安装的版本 |
这张表的用途是帮助项目确认迁移以后到底有没有退化。例如页面切换到 HdsTabs 后,首页、任务和我的三个入口都能点击,这只能说明基础导航还能工作。如果任务页原来的草稿消失了,或者列表最后一个按钮被悬浮栏挡住,迁移依然没有完成。
TabContent 可以复用,业务状态需要重新检查归属
HdsTabs 继续使用 TabContent 作为子组件,HdsTabsOptions 也继承了 TabsOptions。因此,已经存在的首页、任务页和个人页面通常可以继续使用,不需要为了更换导航容器重新复制一套业务界面。
更需要检查的是这些页面把状态保存在哪里。
下面这种状态可以放到导航容器外层:
@State private currentIndex: number = 0;
@State private draftText: string = '';
@State private actionCount: number = 0;
ArkUI Tabs、普通 HdsTabs 和悬浮 HdsTabs 都读取同一份 currentIndex。用户点击页签以后,onChange 再把实际索引保存回来。表单草稿和操作计数同样位于外层,因此更换导航容器时仍然能够保留。
这里还要区分业务状态和界面瞬时状态。表单内容、当前任务和筛选条件通常需要继续保存。滚动位置、输入焦点和局部动画状态不会自动跟着业务数据迁移。项目希望保留滚动位置时,需要使用独立 Scroller 或其他状态机制;希望恢复输入焦点时,也要另外处理焦点交接。
我们的 Demo 主要验证当前页签、草稿和操作计数。它并不能凭空保证所有滚动位置和输入焦点都自动保存。这个边界说明白以后,读者也不会误以为把状态放到父组件就解决了所有页面恢复问题。
可运行的旧方案需要一直留到迁移结束
导航迁移期间,原有 ArkUI Tabs 最好继续保持可构建状态。项目出现 HDS 导入失败、目标设备不支持、悬浮布局遮挡或者发布时间收紧时,团队需要能够快速返回原来的普通导航。如果旧方案已经在迁移初期被删除,回退就会变成重新开发。
我更倾向于让旧方案和新方案共用业务页面,只在外层选择不同导航容器。这样既能比较迁移结果,也能验证业务状态有没有被导航容器绑死。
真实项目可以使用构建配置、页面名单或者功能开关选择导航方案。开关由谁维护、什么时候生效、准备保留多久,都应该在工程说明中写清楚。否则几个月以后再看到一个 useFloatingTabs,很难判断它是长期产品能力,还是当时没有清理的实验代码。
二、导航容器逐层替换
业务状态已经移出导航容器以后,迁移可以开始进入组件层。这时候先别一股脑把悬浮样式、MiniBar、智感握姿和宽窗口策略全部加入。任何一项出现异常,排查范围都会迅速扩大。
比较稳妥的方式,是让每一次修改都能回答一个明确问题。
普通 HdsTabs 先验证基础替换第一轮只把 ArkUI Tabs 替换成普通 HdsTabs。
HdsTabs 从 6.0.0(20) 开始提供,只能用于 Stage 模型,系统能力为 SystemCapability.UIDesign.HDSComponent.Core。它在 Phone、PC/2in1 和 Tablet 上可以正常调用,在 TV 上没有效果。
这一轮保持普通底部导航,不配置 barFloatingStyle,也不打开内容重叠。需要确认的内容包括:
@kit.UIDesignKit可以正常导入- 原有
TabContent可以继续显示 - 初始索引和切换事件保持正常
HdsTabsController与当前 HdsTabs 一一对应- 表单草稿和业务数据没有重新初始化
HdsTabsController 不能同时控制多个 HdsTabs。如果页面同时保留普通和悬浮两种分支,每个分支都需要独立控制器。共享的应该是页签索引和业务数据,不是控制器实例。
普通 HdsTabs 已经稳定以后,项目至少知道 HDS 依赖、TabContent 和基础状态没有问题。后面再出现底部遮挡,原因就更可能来自悬浮布局。
悬浮配置只处理导航位置和内容覆盖
普通 HdsTabs 通过以后,再增加悬浮配置:
.barPosition(BarPosition.End)
.vertical(false)
.barOverlap(true)
.barFloatingStyle({
// 悬浮页签配置
})
barFloatingStyle 从 6.1.0(23) 开始提供。悬浮页签要求 TabBar 位于底部、采用横向排列、开启内容重叠,并使用受支持的底部页签样式或自定义 Builder。
页面进入悬浮状态以后,内容区域可以继续延伸到 TabBar 后方。这一轮需要重新检查末尾列表项、固定按钮、输入框、安全区和系统底部区域。
如果问题只在悬浮模式中出现,普通 HdsTabs 仍然正常,就没有必要重新检查业务请求和整个页面模型。可以先回到 barOverlap、内容底部留白和 barFloatingStyle。
MiniBar 和智感握姿属于可选能力
最小悬浮页签能够稳定工作以后,再评估 MiniBar 和智感握姿。MiniBar 适合展示播放、下载、录音等持续任务。项目没有持续状态时,为了视觉效果加入 MiniBar,反而会占用底部空间。
adaptToHandedness 还需要支持设备和真机条件。代码能够编译,只能说明属性写法被 SDK 接受,无法证明当前设备已经完成左右手跟随。
这里可以把整个迁移过程整理成几个容易回退的步骤。
| 迁移步骤 | 本轮只修改什么 | 需要确认的结果 | 出现异常时返回哪里 |
|---|---|---|---|
| ArkUI Tabs 基线 | 整理共享索引和业务状态 | 原页面行为保持不变 | 原有业务页面 |
| 普通 HdsTabs | 替换容器和控制器 | 三个页签、索引和业务状态正常 | ArkUI Tabs |
| 最小悬浮 HdsTabs | 增加悬浮所需属性 | TabBar 悬浮,末尾内容可操作 | 普通 HdsTabs |
| 可选能力 | 按需加入 MiniBar 或握姿适配 | 每项都有独立验证结果 | 最小悬浮 HdsTabs |
| 多窗口回归 | 检查分屏、自由窗口和大尺寸窗口 | 页面状态在窗口变化后仍然连续 | 已通过的小窗口方案 |

三、canIUse 不能替项目选择导航形态
跨设备项目里,运行时能力判断确实很重要。HarmonyOS 提供全局 canIUse(syscap),用于查询当前系统是否具备指定系统能力。这个接口从 API 8 开始提供,返回一个布尔值。
当前 Demo 使用:
const hdsCoreAvailable: boolean = canIUse(
'SystemCapability.UIDesign.HDSComponent.Core'
);
这个结果可以帮助页面决定是否进入 HDS 分支,但它能够回答的问题非常有限。
true 表示系统具备 HDS Core 能力。它不能说明当前页面一定适合悬浮页签,也不能证明 MiniBar、智感握姿和宽窗口表现已经完成验证。普通 HdsTabs 和悬浮 HdsTabs都标注同一个 HDS Core SysCap,因此 canIUse 无法继续告诉应用应该选择普通模式还是悬浮模式。
这两种模式的选择仍然来自项目策略,例如:
- 当前页面是否适合底部悬浮导航
- 悬浮区域是否已经处理内容遮挡
- 当前版本是否完成 MiniBar 和握姿回归
- 目标窗口形态是否已经验证
- 发布计划能否承担对应回归范围
所以 Demo 中的三个按钮承担不同职责。canIUse 决定 HDS 分支能否使用,页面按钮决定当前希望比较 ArkUI Tabs、普通 HdsTabs 还是悬浮 HdsTabs。
运行时判断不能补救编译期缺失
还有一个经常被忽略的边界。当前 SDK 如果没有 HdsTabs 或 barFloatingStyle 的类型声明,源码会在编译阶段失败。此时即使代码里写了 canIUse,应用也没有机会运行到这个判断。
因此,开发环境和运行设备要分开处理。
编译 SDK 负责提供符号和类型,canIUse 负责查询当前设备的系统能力。项目准备覆盖较低系统版本或者不同设备时,需要保证整个安装包能够编译,同时给不具备对应能力的设备保留合法分支。
SysCap 的要求能力集还会影响应用分发。某项能力如果被列为应用必须具备的能力,缺少该能力的设备可能无法安装应用,运行时回退自然也不会被执行。准备使用 canIUse 完成运行时分支时,需要同时检查项目的 SysCap 配置和目标设备范围。
TV 设备需要单独处理
HdsTabs 在 TV 上没有效果,这属于组件的设备行为差异。
因此,项目需要覆盖 TV 时,不能仅凭 HDS Core SysCap 就假设 HdsTabs 一定能够正常显示。更稳妥的方式是从产品形态或者设备配置层明确保留 ArkUI Tabs 方案。当前 Demo 主要面向 Phone、Tablet 和 PC/2in1,用 canIUse 演示 HDS Core 判断。TV 目标需要在实际项目中增加对应的产品策略,这部分不能依靠一个通用布尔值自动完成。
四、出现异常后先回到普通 HdsTabs
悬浮导航已经加入以后,页面异常经常会集中出现。
有些问题来自 SDK 和导入,有些来自内容覆盖,还有一些来自状态归属。排查时如果始终停留在最复杂的悬浮方案中,多个变量会互相干扰。
我一般会先切回普通 HdsTabs。
普通 HdsTabs 同样异常,说明问题更可能位于 HDS 依赖、TabContent、控制器或共享状态。普通模式正常,悬浮模式异常,范围就缩小到了悬浮属性、内容重叠和底部布局。
| 页面现象 | 优先检查位置 | 常见处理 |
|---|---|---|
找不到 HdsTabs | 当前 SDK、导入路径和 Stage 模型 | 确认 SDK 包含 API 20 及以上 HdsTabs 类型 |
找不到 barFloatingStyle | 当前 SDK 与 API 版本 | 悬浮样式从 6.1.0(23) 开始提供 |
| 普通 HdsTabs 可以显示,底栏没有悬浮 | barPosition、vertical、barOverlap、barFloatingStyle | 回到最小悬浮配置逐项检查 |
| 最后一个列表项被底栏遮挡 | 内容底部留白和固定操作区 | 让可操作内容完整滚出悬浮区域 |
| TabBar 宽度与预期不同 | HdsTabs 自身宽度、高宽比和三档配置 | 不要根据设备名称或者整窗宽度推断档位 |
| 切换页签后索引不同步 | index、onChange 和状态保存位置 | 让所有导航分支共用同一个索引状态 |
| 切换导航后草稿消失 | 业务状态是否位于条件分支内部 | 把草稿和任务状态移动到更稳定的父层 |
| 滚动位置或输入焦点丢失 | 是否显式保存 Scroller 和焦点状态 | 业务状态保留并不等于界面瞬时状态自动恢复 |
| MiniBar 出现位置异常 | 最小悬浮模式是否已经稳定 | 暂时移除 MiniBar,再检查 Builder 和宽度配置 |
| 智感握姿没有变化 | 设备、系统条件和测试姿态 | 编译通过后仍需支持设备完成真机验证 |
| TV 上 HdsTabs 没有显示 | 设备行为和产品分支 | TV 保留 ArkUI Tabs 或其他适配导航 |
| 切换模式后重复请求 | 是否同时创建多套导航页面 | 使用条件分支仅创建当前导航,业务任务由共享状态管理 |
| 系统图标或资源报错 | $r 中的资源是否真实存在 | 使用项目资源或当前 SDK 能够确认的系统资源 |
@Entry 根节点报错 | build() 是否具有合法唯一根容器 | 将导航分支放到同一个根容器内部 |
排查时每次只修改一个变量。
例如普通 HdsTabs 已经正常,加入悬浮配置以后最后一个按钮被遮挡,这时候应该先处理内容底部空间。继续更换控制器或者重建 TabContent,只会把原本已经确认的部分重新带入排查范围。

五、回退方案要在发布以前真正走一遍
准备了三个导航分支,并不等于项目已经具备可靠回退能力。
应急方案长期没有编译和测试,几周以后就可能因为页面参数、资源名称或者状态模型发生变化而失效。到了线上真正需要回退时,才发现普通 HdsTabs 无法构建,这条分支就失去了意义。
当前迁移可以保留三种方案。
悬浮 HdsTabs 适合已经完成以下检查的页面:
- 项目 SDK 和系统范围覆盖悬浮能力
- HDS Core 可以使用
- 一级入口数量适合底部导航
- 内容遮挡和安全区域已经处理
- 多窗口和目标设备已经完成回归
MiniBar 和智感握姿没有完成验证时,可以先关闭可选能力,保留最小悬浮导航。
普通 HdsTabs 适合 HDS 基础导航已经稳定,但悬浮区域、MiniBar、握姿或者宽窗口表现暂时没有足够证据的项目。
回到普通 HdsTabs 时,页面可以移除 barFloatingStyle,关闭 barOverlap,继续复用现有 TabContent、业务状态和 HdsTabsController。视觉范围缩小以后,后续版本仍然可以重新评估悬浮方案。
ArkUI Tabs 适合这些情况:
- 当前开发环境暂时无法引入 UI Design Kit
- 目标设备不具备 HDS Core 能力
- 产品需要覆盖 TV
- 当前发布时间不足以完成 HDS 回归
- 现有普通导航已经满足产品需求
这三种方案之间可以按照下面的关系理解。
| 当前条件 | 可以保留的方案 | 需要暂时关闭什么 |
|---|---|---|
| HDS、悬浮布局和目标设备全部完成验证 | 悬浮 HdsTabs | 未验证的 MiniBar 或握姿能力 |
| HDS 基础导航稳定,悬浮表现仍需补测 | 普通 HdsTabs | barFloatingStyle 与内容重叠 |
| HDS 环境或目标设备条件不满足 | ArkUI Tabs | HDS 相关组件与配置 |
验证回退时,不要停留在首页空白状态。
更有价值的方式是先进入任务页,修改表单,滚动列表,再完成一次业务操作。随后依次切换普通 HdsTabs 和 ArkUI Tabs,检查当前页签、草稿、计数和可操作区域。
| 验收动作 | 应该保留的结果 | 失败以后检查什么 |
|---|---|---|
| 悬浮模式完成一段业务操作 | 状态写入共享模型,底部操作区可以点击 | 状态归属、内容留白和可选能力 |
| 切换到普通 HdsTabs | 当前索引、草稿和业务计数继续保留 | 构造参数、onChange 和父层状态 |
| 切换到 ArkUI Tabs | 页面继续可操作,各控制器没有混用 | 独立控制器和共享索引 |
| 小窗口调整到宽窗口后返回 | 导航方案符合项目规则,任务没有中断 | 窗口策略和业务状态保存 |
| 应用退到后台再返回 | 当前路由和可恢复数据符合产品约定 | 持久化范围和开关读取时机 |
这里还要明确功能开关什么时候生效。
应用冷启动时读取配置,导航可以在页面创建以前确定。配置需要热更新时,正在输入或者播放的页面突然更换导航容器,可能会丢失焦点和局部状态。项目可以让新配置在下次进入页面时生效,也可以专门完成状态交接。
哪一种处理方式都可以,重点是提前写清楚,不能让一个远端布尔值在任意时刻重新创建整张页面。
长期只验证默认的悬浮方案,普通 HdsTabs 和 ArkUI Tabs 会慢慢失去维护。发布候选版本中最好分别构建三种导航,至少完成一遍主要业务流程。产品已经决定永久删除某个方案时,也要同时删除开关、控制器和测试项,避免留下看起来可以回退、实际已经失效的分支。
页面上线以后,现象和处理方式也应该提前对应起来。
底部出现遮挡,可以暂时关闭悬浮样式;HDS 基础组件在目标设备上不可用,需要回到 ArkUI Tabs;业务数据发生错误,则要检查共享状态和页面模型,更换底栏无法修复数据问题。这种对应关系提前准备好以后,真正出现问题时,团队才能选择影响范围较小的方案。
总结
现有 Tabs 迁移到悬浮 HdsTabs,最需要保护的有两部分。一部分是始终可以构建和使用的普通导航,另一部分是独立于导航容器的业务状态。
首页、任务页和个人页面继续使用原来的 TabContent,当前索引、表单草稿和业务数据放到稳定的父层。导航容器按照 ArkUI Tabs、普通 HdsTabs、悬浮 HdsTabs 的顺序逐层替换,每次只增加一组新的变量。出现异常以后,也能够返回上一种已经确认的方案。
canIUse 可以查询 HDS Core SysCap,帮助应用判断当前系统是否具备对应能力。普通 HdsTabs 和悬浮 HdsTabs 的选择仍然需要结合页面结构、目标设备和回归结果。编译环境缺少 HDS API 时,运行时判断无法补救;应用还要覆盖 TV 时,也需要保留独立的导航策略。
回退能力最终要通过真实操作确认。进入任务页、修改草稿、增加业务计数,再切换三种导航,能够比首页空白截图暴露更多问题。滚动位置、输入焦点和未完成任务也要根据项目要求分别处理,不能把它们都归到一个 currentIndex 里。
我目前手里还没有可以测试 HarmonyOS 7 的真机,所以现在只能先通过 HarmonyOS 7 模拟器检查导航切换、状态保存和页面布局。系统能力、设备差异、多窗口体验以及最终交互效果,仍然要以真机实际运行结果为准。
完整代码
Main.ets
/**
* HarmonyOS 7 悬浮页签深度实战 08
*
*/
import {
HdsTabs,
HdsTabsController,
HdsTabsFloatingStyle
} from '@kit.UIDesignKit';
enum NavigationMode {
ARKUI_TABS = 0,
HDS_TABS = 1,
FLOATING_HDS = 2
}
@Entry
@Component
struct Main {
private arkTabsController: TabsController = new TabsController();
private plainHdsController: HdsTabsController =
new HdsTabsController();
private floatingHdsController: HdsTabsController =
new HdsTabsController();
private tabNames: string[] = ['首页', '任务', '我的'];
@State private preferredMode: NavigationMode =
NavigationMode.FLOATING_HDS;
@State private hdsCoreAvailable: boolean = false;
@State private currentIndex: number = 0;
@State private actionCount: number = 0;
@State private draftText: string = '迁移前保留下来的业务草稿';
aboutToAppear(): void {
this.hdsCoreAvailable = canIUse(
'SystemCapability.UIDesign.HDSComponent.Core'
);
}
private effectiveMode(): NavigationMode {
if (!this.hdsCoreAvailable) {
return NavigationMode.ARKUI_TABS;
}
return this.preferredMode;
}
private modeName(mode: NavigationMode): string {
if (mode === NavigationMode.HDS_TABS) {
return '普通 HdsTabs';
}
if (mode === NavigationMode.FLOATING_HDS) {
return '悬浮 HdsTabs';
}
return 'ArkUI Tabs';
}
private tabDescription(index: number): string {
if (index === 1) {
return '切换导航容器后,任务状态和操作次数继续保留。';
}
if (index === 2) {
return '回退只改变导航外壳,不复制个人页面的数据。';
}
return '用同一组业务页面比较三档导航策略。';
}
private pageBottomPadding(): number {
if (this.effectiveMode() === NavigationMode.FLOATING_HDS) {
return 132;
}
return 28;
}
private floatingStyle(): HdsTabsFloatingStyle {
return {
barWidth: {
smallWidth: 228,
mediumWidth: 300,
largeWidth: 328
},
barBottomMargin: 20,
gradientMask: {
maskColor: '#66F4F6FB',
maskHeight: 112
}
};
}
private requestMode(mode: NavigationMode): void {
if (mode !== NavigationMode.ARKUI_TABS &&
!this.hdsCoreAvailable) {
return;
}
this.preferredMode = mode;
}
@Builder
private modeButton(label: string, mode: NavigationMode) {
Button(label, { type: ButtonType.Capsule })
.fontSize(12)
.fontColor(
this.preferredMode === mode ? Color.White : '#43506A'
)
.backgroundColor(
this.preferredMode === mode ? '#5065E8' : '#E9EDF5'
)
.enabled(
mode === NavigationMode.ARKUI_TABS ||
this.hdsCoreAvailable
)
.onClick(() => {
this.requestMode(mode);
})
}
@Builder
private migrationPanel() {
Column({ space: 12 }) {
Column({ space: 4 }) {
Text('导航迁移演练')
.fontSize(25)
.fontWeight(FontWeight.Bold)
.fontColor('#11182C')
.width('100%')
Text('三档导航共用当前 Tab、表单草稿和业务计数')
.fontSize(13)
.fontColor('#68708A')
.width('100%')
}
.width('100%')
.alignItems(HorizontalAlign.Start)
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
this.modeButton('ArkUI Tabs', NavigationMode.ARKUI_TABS)
this.modeButton('普通 HdsTabs', NavigationMode.HDS_TABS)
this.modeButton('悬浮 HdsTabs', NavigationMode.FLOATING_HDS)
}
.width('100%')
Column({ space: 8 }) {
Row() {
Text('HDS Core SysCap')
.fontSize(12)
.fontColor('#68708A')
Blank()
Text(this.hdsCoreAvailable ? '可调用' : '不可调用')
.fontSize(12)
.fontWeight(FontWeight.Medium)
.fontColor(
this.hdsCoreAvailable ? '#2D7A48' : '#B24545'
)
}
.width('100%')
Row() {
Text('实际导航')
.fontSize(12)
.fontColor('#68708A')
Blank()
Text(this.modeName(this.effectiveMode()))
.fontSize(12)
.fontWeight(FontWeight.Medium)
.fontColor('#5065E8')
}
.width('100%')
}
.width('100%')
.padding(14)
.backgroundColor(Color.White)
.borderRadius(16)
}
.width('100%')
.padding({ left: 16, right: 16, top: 18 })
.alignItems(HorizontalAlign.Start)
}
@Builder
private businessPage(index: number) {
Scroll() {
Column({ space: 14 }) {
Column({ space: 5 }) {
Text(this.tabNames[index])
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#11182C')
.width('100%')
Text(this.tabDescription(index))
.fontSize(13)
.fontColor('#68708A')
.lineHeight(19)
.width('100%')
}
.width('100%')
.alignItems(HorizontalAlign.Start)
Column({ space: 10 }) {
Text('共享业务草稿')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#17203A')
.width('100%')
TextInput({ text: this.draftText })
.width('100%')
.height(44)
.backgroundColor('#F4F6FB')
.onChange((value: string) => {
this.draftText = value;
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(18)
.alignItems(HorizontalAlign.Start)
Column({ space: 10 }) {
Row() {
Text('业务操作次数')
.fontSize(13)
.fontColor('#68708A')
Blank()
Text(`${this.actionCount}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#5065E8')
}
.width('100%')
Button('记录一次业务操作', { type: ButtonType.Capsule })
.width('100%')
.height(42)
.fontSize(13)
.backgroundColor('#5065E8')
.onClick(() => {
this.actionCount += 1;
})
}
.width('100%')
.padding(16)
.backgroundColor('#E9EDFF')
.borderRadius(18)
Column({ space: 8 }) {
Text('回退观察点')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#17203A')
.width('100%')
Text('切换三档导航后,当前页、草稿和计数都应保持。')
.fontSize(12)
.fontColor('#68708A')
.lineHeight(18)
.width('100%')
Text(`当前外壳:${this.modeName(this.effectiveMode())}`)
.fontSize(12)
.fontColor('#5065E8')
.width('100%')
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(18)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding({
left: 16,
right: 16,
top: 14,
bottom: this.pageBottomPadding()
})
}
.width('100%')
.height('100%')
.scrollBar(BarState.Off)
.backgroundColor('#F4F6FB')
}
@Builder
private arkUiNavigation() {
Tabs({
barPosition: BarPosition.End,
index: this.currentIndex,
controller: this.arkTabsController
}) {
ForEach(
this.tabNames,
(item: string, index: number) => {
TabContent() {
this.businessPage(index)
}
.tabBar(
new BottomTabBarStyle(
$r('sys.media.ohos_ic_public_clock'),
item
)
)
},
(item: string) => item
)
}
.vertical(false)
.scrollable(true)
.onChange((index: number) => {
this.currentIndex = index;
})
.width('100%')
.height('100%')
}
@Builder
private plainHdsNavigation() {
HdsTabs({
index: this.currentIndex,
controller: this.plainHdsController
}) {
ForEach(
this.tabNames,
(item: string, index: number) => {
TabContent() {
this.businessPage(index)
}
.tabBar(
new BottomTabBarStyle(
$r('sys.media.ohos_ic_public_clock'),
item
)
)
},
(item: string) => item
)
}
.barPosition(BarPosition.End)
.vertical(false)
.scrollable(true)
.barOverlap(false)
.onChange((index: number) => {
this.currentIndex = index;
})
.width('100%')
.height('100%')
}
@Builder
private floatingHdsNavigation() {
HdsTabs({
index: this.currentIndex,
controller: this.floatingHdsController
}) {
ForEach(
this.tabNames,
(item: string, index: number) => {
TabContent() {
this.businessPage(index)
}
.tabBar(
new BottomTabBarStyle(
$r('sys.media.ohos_ic_public_clock'),
item
)
)
},
(item: string) => item
)
}
.barPosition(BarPosition.End)
.vertical(false)
.scrollable(true)
.barOverlap(true)
.barFloatingStyle(this.floatingStyle())
.onChange((index: number) => {
this.currentIndex = index;
})
.width('100%')
.height('100%')
}
build() {
Column({ space: 10 }) {
this.migrationPanel()
Column() {
if (this.effectiveMode() === NavigationMode.ARKUI_TABS) {
this.arkUiNavigation()
} else if (this.effectiveMode() === NavigationMode.HDS_TABS) {
this.plainHdsNavigation()
} else {
this.floatingHdsNavigation()
}
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#F4F6FB')
}
}
更多推荐


所有评论(0)