前言

下载一份离线资料时,用户通常不会持续停留在任务页。他可能返回首页继续浏览,也可能切换到“我的”修改设置。任务还在运行,进度和暂停入口却仍保留在刚才那一页,此时要求用户沿原路重新进入任务页面,操作成本会明显增加。

把下载卡片复制到三个 TabContent 也解决不了问题。三张卡片如果各自保存进度,就会显示出不同数字;如果每张卡片都接入一次暂停逻辑,任务控制入口又会散落到页面各处。悬浮页签的 MiniBar 适合展示这种跨 Tab 可见的小型状态,但它只负责展示和交互区域,不是下载器、播放器或后台任务管理器。

当前接口中没有一个可单独创建的 MiniBar 组件。它是 HdsTabsFloatingStyle 的可选配置,通过 barFloatingStyle() 中的 miniBar 接入 HdsTabs,核心类型是 HdsTabsMiniBar。其中必填的 miniBarBuilder 提供自定义内容,HdsTabsController.applyMiniBarStyle() 负责应用侧发起展开或折叠。

MiniBar 从 6.1.0(23) 开始提供,只能用于 Stage 模型,系统能力为 SystemCapability.UIDesign.HDSComponent.Core,在 TV 上没有效果。

一、MiniBar 是 HdsTabs 的状态窗口

悬浮页签需要满足底部横向布局的基本条件:barPositionBarPosition.EndverticalfalsebarOverlaptrue。在这组条件上为 barFloatingStyle() 增加 miniBar 配置,HdsTabs 才同时拥有悬浮 TabBar 和 MiniBar。没有配置 miniBar 时,页面仍然只是悬浮页签栏。

miniBarBuilder 接受 CustomBuilderComponentContent。Demo 使用 Builder,把任务名称、进度和暂停状态投影到底部。Builder 读取的是外层 Main 保存的任务字段;切换首页、任务、我的时,三个内容页发生变化,外层 HdsTabs 和它的 MiniBar 仍是同一个实例,因而会继续读取同一份状态。

接口只要求一份 miniBarBuilder,没有“折叠 Builder”和“展开 Builder”两套入口。我们的Demo 根据回调确认的 actualMiniBarStyle 决定显示密度:折叠时仅保留百分比和精简进度条,展开后增加任务名称与运行状态。两种形态仍读取同一任务模型,不会出现展开内容更新了、折叠内容还保留旧值。enableMiniBarClip 默认是 true,超出 MiniBar 边界的 Builder 内容会被裁剪;enableMiniBarBackground 默认也是 true,MiniBar 跟随页签栏背景。内容设计需要在边界内完成,不能依靠关闭裁剪把按钮绘制到可点击区域之外。

这个结构里有三种职责:

对象 负责什么 不负责什么
任务模型 任务名称、进度、暂停状态、真实执行与恢复 不决定底栏排版方式
MiniBar Builder 把关键状态压缩成持续可见的 UI 不创建下载任务,也不自动让任务后台运行
HdsTabs 与 Controller MiniBar、TabBar 的布局协调,展开折叠与回调 不保存业务进度,不替项目处理进程重启

普通页面卡片适合当前页面的完整信息,例如下载来源、文件列表和错误详情。

MiniBar 的空间有限,更适合回答三个简短问题:正在处理什么,进行到哪里,当前是否暂停。详细操作仍然回到任务页完成。十几个按钮如果都集中在 MiniBar 中,它会从状态入口变成一块拥挤的操作面板,也会挤压 TabBar 的可用宽度。

Demo 没有启动网络请求,也没有假装后台下载。点击“推进 8%”只修改本地实验进度,点击“暂停/继续”只切换布尔状态。这种做法能单独验证 UI 状态关系,不会把网络权限、任务调度和异常重试混进组件实验。

二、请求状态和组件实际状态要分开

展开、折叠使用 HdsBarStyleCOLLAPSE 表示折叠,EXPAND 表示展开。应用主动控制时调用:

this.tabsController.applyMiniBarStyle(HdsBarStyle.EXPAND);

这个方法返回 void,切换会使用组件默认动效。按钮调用后,只能确定应用已经发出展开请求。Demo 因此保存 requestedMiniBarStyle,实际样式则从 MiniBar 回调更新,避免按钮文字先行、底部仍在动效中时就把请求当作完成结果。

首次创建也有明确的宽度规则。HdsTabs 宽度小于 600vp 时,MiniBar 默认折叠,miniBarStyle 配置在这个范围内生效;宽度大于 600vp 时首次创建为展开样式。miniBarWidth 可以分别配置 smallWidthmediumWidthlargeWidth,展开宽度上限为 328vp,不支持百分比。手机竖屏上固定一个接近平板的宽度,MiniBar 和 TabBar 可能互相挤压。

三档宽度按 HdsTabs 窗口条件划分,设备名单不能代替这套分档。smallWidth 用于 HdsTabs 小于 440vp 的场景;mediumWidth 覆盖 440~600vp,以及 600~840vp 中部分高宽比场景;largeWidth 覆盖大于 840vp,以及 600~840vp 中另一部分高宽比场景。窗口拖动或折叠状态变化后,同一台设备也可能跨档。宽度测试需要直接调整窗口,也不能把“手机固定对应 small、平板固定对应 large”作为判断规则。

设置宽度时,我会让折叠形态仅凭最精简的信息也能辨认任务,展开形态则分配名称和状态文字。Demo 的三档展开宽度是 248vp、300vp、328vp,其中 328vp 已到接口上限;TabBar 另有自己的分档宽度。项目若有四个以上页签或更长的本地化文案,需要在小尺寸窗口中实测两者如何组合。空间不足时缩短 MiniBar 文案,不能继续增加宽度。

API 26 还提供 HdsBarLayoutMode.HORIZONTALVERTICAL,它们从 6.1.1(24) 开始生效。Demo 显式选择水平左右布局。在水平场景中,HdsTabs 会根据自身宽度以及两块 Bar 的展开折叠状态调整整体位置:小于 440vp、440~600vp、大于 600vp 的处理并不相同。业务代码无需根据设备名称手工计算 MiniBar 的绝对横坐标。

组件状态可以通过三组回调确认:

  • onBarStyleChange 同时返回 MiniBar 样式、TabBar 样式、两者当前宽度以及变更模式。
  • onMiniBarAnimationStart 返回动效开始时的样式和动效结束后的目标宽度。
  • onMiniBarAnimationEnd 返回动效结束后的 MiniBar 样式。

HdsTabsBarChangeMode 可以区分变化来源:NORMAL 对应屏幕尺寸变化等普通更新,USER_CLICK 对应用户点击折叠的 MiniBar 或 TabBar,APP_TRIGGER 对应控制器触发。旋转、折叠屏开合或自由窗口缩放都可能改变底栏组合,只监听顶部“展开”按钮会漏掉这些变化。

一次应用触发展开,可以按“保存请求、调用 Controller、收到动效开始、收到样式变化、收到动效结束”来记录。回调之间不要无条件调用 applyMiniBarStyle(),否则组件报告一次变化以后,业务又发出同样命令,容易形成重复动效。回调适合确认和记录,新的展开折叠命令应来自清晰的用户操作或业务规则。

onBarStyleChange 返回 MiniBar 与 TabBar 的整组结果,适合更新调试面板和布局日志;onMiniBarAnimationEnd 只确认 MiniBar 动效结束后的样式。两者可能服务于不同用途,不必都触发下载埋点。任务暂停、继续属于业务事件,底栏由窗口变化自动折叠属于 UI 事件,把两类统计混在一起会夸大用户操作次数。

三、跨 Tab 状态保留取决于状态归属

我的 Demo 把 taskProgressisPausedtaskName 保存在 HdsTabs 外层的 Main 中。三个 TabContent 与 MiniBar 都读取它们。用户从任务页切换到“我的”,只会改变当前内容索引,不会创建第二份任务状态。任一入口推进进度,MiniBar 和任务页显示的数字都会来自同一个字段。

展开折叠状态与任务状态也没有因果关系。收起 MiniBar 只是减少底部占用,任务不会自动暂停;展开 MiniBar 只是显示更多文字,任务也不会自动继续。HdsTabsController 的 applyHideAnimation() 会同时处理页签栏和 MiniBar 的隐藏动效,当前接口没有“只隐藏 MiniBar 并顺便停止任务”的控制器方法。业务若需要在任务完成后移除 MiniBar,需要由任务状态驱动页面配置变化,并单独处理完成记录,不能依赖 UI 消失来结束任务。

三层状态分开保存,可以避免相互污染:

状态层 Demo 字段 推荐更新时点
业务状态 taskProgressisPaused 任务服务或明确的用户操作
展示请求 requestedMiniBarStyle 应用调用 Controller 之前
组件实况 actualMiniBarStyle、宽度、变更模式 HdsTabs 回调到达时

这种分层可以直接缩小排查范围。MiniBar 文字不更新时,检查业务状态是否变化;按钮点击后没有展开时,核对请求字段和动效回调;窗口变化后位置异常,则检查 onBarStyleChange 返回的两块 Bar 宽度。这些问题全部合并到一个 isExpanded 里,合并后只能看到一个布尔值,无法判断状态断在哪一段。

跨 Tab 保留不等于页面销毁后永久保留。@State 与所属组件共享生命周期,组件销毁时状态也会消失。Demo 的字段足以观察同一个 HdsTabs 内切换;如果任务要跨页面、跨 UIAbility 或在应用重启后恢复,真实任务状态应上移到项目已有的 ViewModel、任务服务或合适的应用级状态容器,必要时持久化任务标识与进度。不要为了 MiniBar 额外创建一份“显示专用进度”,否则恢复后会出现任务服务是 68%,底栏仍显示 42% 的情况。

常见生命周期可以逐项检查:

场景 Main 中的 @State 真实任务的处理方式
同一 HdsTabs 内切换 Tab 继续存在 继续向同一状态源推送进度
MiniBar 展开或折叠 继续存在 不因展示形态改变而启停
整个 Main 被条件渲染移除 随组件销毁 由上层模型或任务服务持有
应用进程结束后重新启动 不能依赖原组件状态 根据持久化任务标识查询并恢复

真正需要持久化的通常是能重新找到任务的标识、任务参数和可恢复进度。某一帧的动效文字、当前宽度或 USER_CLICK 变更来源无需保存。恢复 MiniBar 前,要向任务系统确认任务仍有效;已经失败、取消或完成的任务应进入对应结果状态,不能因为缓存里还有 58% 就继续显示“任务进行中”。

组件重建时,从真实任务源恢复业务状态,并由新的 MiniBar Builder 订阅这份状态。MiniBar 的展开偏好是否需要恢复取决于业务:播放入口可能值得保留用户上次选择,普通下载提示通常可以接受系统按窗口宽度重新决定初始样式。业务进度需要可靠,纯展示样式可以跟随当前窗口,这是两类不同的恢复要求。

四、通过固定操作检查持续状态

完整页面提供“暂停/继续”“推进 8%”“展开 MiniBar”“收起 MiniBar”四个按钮,三页内容都显示同一任务摘要。大家运行时可以依次观察:

  1. 在首页把进度从 42% 推进到 50%,确认 MiniBar 同步显示。
  2. 切换到任务页,推进一次,确认任务页和 MiniBar 都变为 58%。
  3. 切换到“我的”,点击暂停,确认 MiniBar 状态变为已暂停,进度不归零。
  4. 依次点击展开与收起,比较请求样式、实际样式、动效文字和两块 Bar 宽度。
  5. 改变 API 26 模拟器窗口宽度,记录变更模式与 MiniBar、TabBar 的组合位置。

进度到 100% 后还要完成一轮边界检查。Demo 会禁用继续推进,并将摘要更新为“任务已完成”,但不会自动移除 MiniBar。生产页面可以在完成后短暂保留结果入口,也可以由业务策略移除;无论选择哪种方式,任务状态落库和结果通知完成后才能处理底栏展示。暂停状态下点击“推进 8%”也不能改变数字,这能检查 MiniBar 看到的究竟是任务源,还是某个按钮单独维护的展示值。

如果结果不符合预期,可以按现象排查:

现象 优先检查
切换 Tab 后进度归零 任务状态是否定义在被替换的 TabContent 内
顶部显示已展开,MiniBar 仍在动 是否把请求字段当成了动效完成状态
用户点击引起变化却没有记录 是否只处理 APP_TRIGGER,没有接入 onBarStyleChange
小尺寸窗口中两块 Bar 互相挤压 展开宽度是否超过场景需要,是否绕过 HdsTabs 自带布局
重新进入页面后任务消失 真实任务状态是否只保存在页面 @State
MiniBar 隐藏后任务被误判完成 是否把 UI 可见性当成任务生命周期

MiniBar 也有不合适的场景。几秒钟就结束的操作采用 Toast 或页面内反馈即可;需要大量字段、表单和危险操作的任务应该进入完整详情页;没有跨 Tab 可见价值的筛选条件保留在原页面即可。只有状态持续时间较长、用户确实会离开当前 Tab、又能压缩成少量关键信息时,MiniBar 才能减少找回任务的成本。

Builder 还应保持纯展示职责。任务启动、进度推进和持久化由业务事件触发,miniBarBuilder 只读取结果并生成界面。如果 Builder 中包含定时器、网络请求或状态写入,界面重建时可能重复启动任务,进度变化又会触发下一轮重建。排查重复请求时,可以移除 MiniBar,确认任务源只运行一份;恢复 Builder 后,观察投影是否一致。

任务由后台服务维护时,页面重新进入需要订阅已有任务状态,不能为了恢复 MiniBar 另行创建一份同名任务。订阅解除也要跟随页面生命周期处理,避免旧页面继续接收进度并重复刷新。

上线前还要在系统字体放大和较长文案条件下完成一次小尺寸窗口检查。MiniBar 中的任务名称需要允许截断,百分比和暂停状态要优先保留;如果放大后连核心状态也无法辨认,就要缩减内容或调整为进入任务页的简短入口,不要只缩小字号来容纳全部内容。

总结

MiniBar 通过 HdsTabs 的 barFloatingStyle().miniBar 接入,Builder 负责呈现任务摘要,Controller 的 applyMiniBarStyle() 发起展开或折叠。应用请求、动效过程和组件最终样式分别保存,由回调确认实际状态,窗口变化和用户点击就不会被漏掉。

持续任务的名称、进度、暂停状态属于业务模型。MiniBar 收起、展开或随底栏隐藏都不能直接改变任务生命周期;跨 Tab 只需要共享同一份上层状态,跨页面销毁和应用重启则要回到项目现有的状态管理与持久化方案。

我目前手里还没有可以测试 HarmonyOS 7 的真机,所以现在只能先在模拟器里验证,最终效果还是要以真机实际运行结果为准。

完整代码

Main.ets

/**
 * HarmonyOS 7 悬浮页签深度实战 05
 *
 */

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

@Entry
@Component
struct Main {
  private tabsController: HdsTabsController =
    new HdsTabsController();

  @State private currentIndex: number = 0;
  @State private taskName: string = 'HarmonyOS 7 离线资料包';
  @State private taskProgress: number = 42;
  @State private isPaused: boolean = false;
  @State private requestedMiniBarStyle: HdsBarStyle =
    HdsBarStyle.COLLAPSE;
  @State private actualMiniBarStyle: HdsBarStyle =
    HdsBarStyle.COLLAPSE;
  @State private actualTabBarStyle: HdsBarStyle =
    HdsBarStyle.EXPAND;
  @State private miniBarWidth: number = 0;
  @State private tabBarWidth: number = 0;
  @State private changeModeText: string = '等待样式回调';
  @State private animationText: string = '尚未发起展开或折叠';

  private tabName(index: number): string {
    if (index === 1) {
      return '任务';
    }
    if (index === 2) {
      return '我的';
    }
    return '首页';
  }

  private styleName(style: HdsBarStyle): string {
    return style === HdsBarStyle.EXPAND ? '展开' : '折叠';
  }

  private modeName(mode: HdsTabsBarChangeMode): string {
    if (mode === HdsTabsBarChangeMode.USER_CLICK) {
      return '用户点击';
    }
    if (mode === HdsTabsBarChangeMode.APP_TRIGGER) {
      return '应用触发';
    }
    return '普通更新';
  }

  private taskStatusText(): string {
    if (this.taskProgress >= 100) {
      return '任务已完成';
    }
    return this.isPaused ? '任务已暂停' : '任务进行中';
  }

  private toggleTask(): void {
    if (this.taskProgress >= 100) {
      return;
    }
    this.isPaused = !this.isPaused;
  }

  private advanceTask(): void {
    if (this.isPaused || this.taskProgress >= 100) {
      return;
    }
    this.taskProgress = Math.min(100, this.taskProgress + 8);
  }

  private requestMiniBarStyle(style: HdsBarStyle): void {
    this.requestedMiniBarStyle = style;
    this.animationText =
      `应用请求:${this.styleName(style)} MiniBar`;
    this.tabsController.applyMiniBarStyle(style);
  }

  @Builder
  private taskMiniBar() {
    Row({ space: 8 }) {
      Column({ space: 3 }) {
        Text(`${this.taskProgress}%`)
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .fontColor('#5065E8')

        Progress({
          value: this.taskProgress,
          total: 100,
          type: ProgressType.Linear
        })
          .width(52)
          .height(4)
          .color('#5065E8')
          .backgroundColor('#DDE2F5')
      }
      .alignItems(HorizontalAlign.Start)

      if (this.actualMiniBarStyle === HdsBarStyle.EXPAND) {
        Column({ space: 2 }) {
          Text(this.taskName)
            .fontSize(12)
            .fontWeight(FontWeight.Medium)
            .fontColor('#17203A')
            .maxLines(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .width('100%')

          Text(this.taskStatusText())
            .fontSize(10)
            .fontColor(this.isPaused ? '#B56A22' : '#68708A')
            .width('100%')
        }
        .layoutWeight(1)
        .alignItems(HorizontalAlign.Start)
      }
    }
    .width('100%')
    .height(56)
    .padding({ left: 10, right: 12 })
  }

  @Builder
  private controlPanel() {
    Column({ space: 8 }) {
      Row({ space: 8 }) {
        Button(this.isPaused ? '继续任务' : '暂停任务')
          .layoutWeight(1)
          .height(38)
          .fontSize(12)
          .onClick(() => {
            this.toggleTask();
          })

        Button('推进 8%')
          .layoutWeight(1)
          .height(38)
          .fontSize(12)
          .enabled(!this.isPaused && this.taskProgress < 100)
          .onClick(() => {
            this.advanceTask();
          })
      }
      .width('100%')

      Row({ space: 8 }) {
        Button('展开 MiniBar')
          .layoutWeight(1)
          .height(38)
          .fontSize(12)
          .fontColor('#5065E8')
          .backgroundColor('#EEF1FF')
          .onClick(() => {
            this.requestMiniBarStyle(HdsBarStyle.EXPAND);
          })

        Button('收起 MiniBar')
          .layoutWeight(1)
          .height(38)
          .fontSize(12)
          .fontColor('#5065E8')
          .backgroundColor('#EEF1FF')
          .onClick(() => {
            this.requestMiniBarStyle(HdsBarStyle.COLLAPSE);
          })
      }
      .width('100%')
    }
    .width('100%')
  }

  @Builder
  private statePanel() {
    Column({ space: 6 }) {
      Row() {
        Text('当前页面')
          .fontSize(12)
          .fontColor('#68708A')
        Blank()
        Text(this.tabName(this.currentIndex))
          .fontSize(12)
          .fontWeight(FontWeight.Medium)
          .fontColor('#17203A')
      }
      .width('100%')

      Row() {
        Text('MiniBar 请求 / 实际')
          .fontSize(12)
          .fontColor('#68708A')
        Blank()
        Text(
          `${this.styleName(this.requestedMiniBarStyle)} / ` +
          `${this.styleName(this.actualMiniBarStyle)}`
        )
          .fontSize(12)
          .fontWeight(FontWeight.Medium)
          .fontColor('#5065E8')
      }
      .width('100%')

      Row() {
        Text(
          `MiniBar / TabBar ${this.styleName(this.actualTabBarStyle)}`
        )
          .fontSize(12)
          .fontColor('#68708A')
        Blank()
        Text(
          `${this.miniBarWidth.toFixed(0)}vp / ` +
          `${this.tabBarWidth.toFixed(0)}vp`
        )
          .fontSize(12)
          .fontColor('#17203A')
      }
      .width('100%')

      Text(`${this.changeModeText}${this.animationText}`)
        .fontSize(11)
        .fontColor('#747C92')
        .lineHeight(17)
        .width('100%')
    }
    .width('100%')
    .padding(13)
    .backgroundColor(Color.White)
    .borderRadius(18)
    .alignItems(HorizontalAlign.Start)
  }

  @Builder
  private tabPage(title: string, description: string) {
    Scroll() {
      Column({ space: 14 }) {
        Text(title)
          .fontSize(27)
          .fontWeight(FontWeight.Bold)
          .fontColor('#11182C')
          .width('100%')

        Text(description)
          .fontSize(14)
          .fontColor('#68708A')
          .lineHeight(21)
          .width('100%')

        Column({ space: 8 }) {
          Text(this.taskName)
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .fontColor('#17203A')
            .width('100%')

          Text(`${this.taskProgress}% · ${this.taskStatusText()}`)
            .fontSize(22)
            .fontWeight(FontWeight.Bold)
            .fontColor('#5065E8')
            .width('100%')

          Progress({
            value: this.taskProgress,
            total: 100,
            type: ProgressType.Linear
          })
            .width('100%')
            .height(6)
            .color('#5065E8')
            .backgroundColor('#DDE2F5')

          Text('切换页签以后,这里与 MiniBar 继续读取同一份状态。')
            .fontSize(12)
            .fontColor('#68708A')
            .lineHeight(18)
            .width('100%')
        }
        .width('100%')
        .padding(18)
        .backgroundColor(Color.White)
        .borderRadius(20)
        .alignItems(HorizontalAlign.Start)
      }
      .width('100%')
      .padding({
        left: 20,
        right: 20,
        top: 16,
        bottom: 150
      })
    }
    .width('100%')
    .height('100%')
    .scrollBar(BarState.Off)
    .backgroundColor('#F4F6FB')
  }

  build() {
    Column({ space: 10 }) {
      Column({ space: 5 }) {
        Text('HarmonyOS 7 MiniBar')
          .fontSize(26)
          .fontWeight(FontWeight.Bold)
          .fontColor('#11182C')
          .width('100%')

        Text('一份任务状态,三个页面持续可见')
          .fontSize(14)
          .fontColor('#68708A')
          .width('100%')
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start)

      this.controlPanel()
      this.statePanel()

      Column() {
        HdsTabs({
          controller: this.tabsController
        }) {
          TabContent() {
            this.tabPage('首页', '浏览内容时也能看到长期任务进度。')
          }
          .tabBar(
            new BottomTabBarStyle(
              $r('sys.media.ohos_ic_public_clock'),
              '首页'
            )
          )

          TabContent() {
            this.tabPage('任务', '这里可以承载完整任务详情和异常处理。')
          }
          .tabBar(
            new BottomTabBarStyle(
              $r('sys.media.ohos_ic_public_clock'),
              '任务'
            )
          )

          TabContent() {
            this.tabPage('我的', '切到个人页后,任务状态仍由外层保存。')
          }
          .tabBar(
            new BottomTabBarStyle(
              $r('sys.media.ohos_ic_public_clock'),
              '我的'
            )
          )
        }
        .barPosition(BarPosition.End)
        .vertical(false)
        .scrollable(true)
        .barOverlap(true)
        .animationDuration(240)
        .barFloatingStyle({
          barWidth: {
            smallWidth: 228,
            mediumWidth: 240,
            largeWidth: 240
          },
          barBottomMargin: 20,
          miniBar: {
            miniBarBuilder: () => this.taskMiniBar(),
            miniBarWidth: {
              smallWidth: 248,
              mediumWidth: 300,
              largeWidth: 328
            },
            miniBarStyle: this.actualMiniBarStyle,
            enableMiniBarBackground: true,
            enableMiniBarClip: true,
            barLayoutMode: HdsBarLayoutMode.HORIZONTAL,
            onBarStyleChange: (
              miniBarStyle: HdsBarStyle,
              tabBarStyle: HdsBarStyle,
              miniBarWidth: number,
              tabBarWidth: number,
              mode: HdsTabsBarChangeMode
            ) => {
              this.actualMiniBarStyle = miniBarStyle;
              this.actualTabBarStyle = tabBarStyle;
              this.miniBarWidth = miniBarWidth;
              this.tabBarWidth = tabBarWidth;
              this.changeModeText =
                `变化来源:${this.modeName(mode)},TabBar ` +
                `${this.styleName(tabBarStyle)}`;
            },
            onMiniBarAnimationStart: (
              style: HdsBarStyle,
              width: number
            ) => {
              this.animationText =
                `动效开始:${this.styleName(style)}` +
                `结束宽度 ${width.toFixed(0)}vp`;
            },
            onMiniBarAnimationEnd: (style: HdsBarStyle) => {
              this.actualMiniBarStyle = style;
              this.animationText =
                `动效结束:MiniBar ${this.styleName(style)}`;
            },
            onTabBarAnimationStart: (
              style: HdsBarStyle,
              width: number
            ) => {
              this.actualTabBarStyle = style;
              this.animationText =
                `TabBar 动效开始:${this.styleName(style)}` +
                `结束宽度 ${width.toFixed(0)}vp`;
            }
          }
        })
        .onChange((index: number) => {
          this.currentIndex = index;
        })
        .width('100%')
        .height('100%')
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .padding({
      left: 16,
      right: 16,
      top: 20
    })
    .backgroundColor('#F4F6FB')
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐