【HarmonyOS 7 沉浸光感深度实战】 08 HDS Navigation、Tabs 与 MiniBar 接入

文章目录

    • 前言
    • [一、HDS 材质先看类型和等级](#一、HDS 材质先看类型和等级)
    • [二、HdsNavigation、HdsTabs 和 MiniBar 放在一起理解](#二、HdsNavigation、HdsTabs 和 MiniBar 放在一起理解)
      • [标题栏材质写在 titleBar.style 中](#标题栏材质写在 titleBar.style 中)
      • [HdsTabs 的悬浮样式有三个基础条件](#HdsTabs 的悬浮样式有三个基础条件)
      • [MiniBar 和悬浮页签共用底部空间](#MiniBar 和悬浮页签共用底部空间)
    • [三、现有项目先看页面结构,再决定要不要接 HDS](#三、现有项目先看页面结构,再决定要不要接 HDS)
      • [只改一个普通组件,继续使用 ArkUI](#只改一个普通组件,继续使用 ArkUI)
      • [标题栏和底部导航准备一起调整时,再考虑 HDS](#标题栏和底部导航准备一起调整时,再考虑 HDS)
      • [MiniBar 最好对应一个持续存在的状态](#MiniBar 最好对应一个持续存在的状态)
      • [材质等级优先从 ADAPTIVE 开始](#材质等级优先从 ADAPTIVE 开始)
    • 总结
    • 完整代码

前言

页面做到标题栏和底部导航以后,我通常不会再把它们当成普通的 ColumnRow 去处理。

原因也比较实际。标题栏除了显示标题,还要处理返回、菜单、安全区和滚动联动;底部页签需要考虑内容区叠加、窗口宽度和页面切换;如果页面还有播放、下载或者持续运行的任务,底部往往还需要留出一个长期可见的小区域。

这些需求叠在一起以后,继续用普通组件拼框架,代码会越来越分散。HDS 提供的 HdsNavigationHdsTabs 和 MiniBar 更适合处理这一层页面结构。HdsNavigation 管标题栏和导航容器,HdsTabs 管内容与底部页签,MiniBar 则可以和悬浮页签保持同一高度,在旁边放一块自定义状态区域。悬浮页签和 MiniBar 从 HarmonyOS 6.1.0(23)开始提供。

材质配置也跟普通 ArkUI 组件不同。HDS 使用 hdsMaterial 中的 MaterialTypeMaterialLevel,标题栏按钮和底部悬浮页签分别通过自己的 systemMaterialEffect 接入沉浸光感。从 6.1.0(23)开始,HDS 导航和底部页签都支持这套材质能力。

我在这类页面里更关心的是框架是否顺手。标题栏、底部页签和 MiniBar 能不能在同一套结构中稳定工作,材质策略能不能跟着设备能力调整,这些问题理顺以后,视觉细节反而好处理。

当前实验会搭一张三页签页面。顶部使用 HdsNavigation,底部使用悬浮 HdsTabs,旁边再加入一块 MiniBar。页面同时查询当前环境支持的 HDS 材质类型,默认使用系统自适应等级,也保留一组按照查询结果选择材质等级的实验入口。

目前我的测试设备还没有 HarmonyOS 7 实机测试权限,因此当前先在模拟器中检查接口、页面结构和基础布局。标题栏按钮材质、悬浮页签层次、MiniBar 以及不同设备上的最终效果,仍建议在具备权限的真机上继续检查。

一、HDS 材质先看类型和等级

普通 ArkUI 组件里,我们习惯使用 ImmersiveStyle.THINREGULAR 这类样式。进入 HDS 以后,配置方式换成了 MaterialTypeMaterialLevel

先导入:

ts 复制代码
import { hdsMaterial } from '@kit.UIDesignKit';

hdsMaterial 从 6.1.0(23)开始提供,只支持 Stage 模型,可以通过 getSystemMaterialTypes() 查询设备支持的材质类型。

MaterialType 负责材质类型

当前 MaterialType 包含三项:

枚举 含义
NONE 无材质效果
ADAPTIVE 自适应系统材质,默认采用沉浸式材质
IMMERSIVE 沉浸式材质

页面希望交给系统处理时,可以从下面的配置开始。

ts 复制代码
materialType:
  hdsMaterial.MaterialType.ADAPTIVE

我更倾向于把它当成正常项目的默认选择。页面没有明确的设备限制,也没有强制要求某一种固定材质时,让系统根据当前能力处理会省掉很多设备判断。

MaterialLevel 负责显示等级

材质类型确定以后,还有一层等级。

MaterialLevel 当前提供 EXQUISITEGENTLESMOOTHADAPTIVEEXQUISITE 使用的性能资源更多,SMOOTH 更偏向流畅性,ADAPTIVE 会根据设备性能自行调整。官方当前仍然推荐优先使用 ADAPTIVE

等级 页面里可以怎么理解
EXQUISITE 偏完整的材质表现
GENTLE 效果与资源开销相对平衡
SMOOTH 更偏向流畅和温控
ADAPTIVE 根据设备能力自动决定

因此,一套比较稳妥的默认配置就是:

ts 复制代码
systemMaterialEffect: {
  materialType:
    hdsMaterial.MaterialType.ADAPTIVE,

  materialLevel:
    hdsMaterial.MaterialLevel.ADAPTIVE
}

需要自己决定等级时,先查设备能力

HDS 已经提供了下面的方式用来查看当前设备支持哪些材质类型。

ts 复制代码
const types: Array<hdsMaterial.MaterialType> =
  hdsMaterial.getSystemMaterialTypes();

如果返回结果包含 IMMERSIVE,可以选择 EXQUISITEGENTLE;如果没有支持 IMMERSIVE,则建议使用 SMOOTH,降低卡顿和发热风险。

所以我们的实验页里可以准备两套策略。

第一套继续交给系统:

text 复制代码
ADAPTIVE
+
ADAPTIVE

第二套根据查询结果:

text 复制代码
支持 IMMERSIVE
→ GENTLE

未确认 IMMERSIVE
→ SMOOTH

我不会把第二套当成固定业务规则。它更适合帮助我们理解 MaterialTypeMaterialLevel 的关系。项目没有特殊要求时,继续使用系统自适应反而更省事。

材质策略有了以后,下面再看它怎样落到标题栏和底部导航上。

二、HdsNavigation、HdsTabs 和 MiniBar 放在一起理解

我更喜欢把这三个组件看成一整张页面框架。

text 复制代码
HdsNavigation
│
├── 标题栏
│   ├── 页面标题
│   └── 功能按钮
│
└── HdsTabs
    ├── 首页内容
    ├── 发现内容
    ├── 我的内容
    │
    └── 悬浮底部区域
        ├── TabBar
        └── MiniBar

HdsNavigation 从 5.1.0(18)开始提供导航容器能力,6.0.0(20)以后官方建议通过 bindToScrollablebindToNestedScrollable 与可滚动组件建立关联,用于标题栏模糊和滚动显示等效果。

这次实验不会把所有导航效果都塞进去。页面先保留标题栏、三个菜单按钮和滚动内容,重点看 HDS 框架与沉浸材质怎样配合。

标题栏材质写在 titleBar.style 中

HDS 标题栏的沉浸材质入口位于 TitleBarStyleOptions.systemMaterialEffect,主要作用于返回按钮、菜单按钮等标题栏可操作区域。

先准备右侧菜单:

ts 复制代码
private menus:
  HdsNavigationMenuContentOptions = {
    value: [
      {
        content: {
          label: '编辑',
          icon:
            $r('sys.symbol.square_and_pencil')
        }
      },
      {
        content: {
          label: '收藏',
          icon:
            $r('sys.symbol.star')
        }
      },
      {
        content: {
          label: '更多',
          icon:
            $r('sys.symbol.more')
        }
      }
    ]
  };

随后把材质写入标题栏:

ts 复制代码
.titleBar({
  content: {
    title: {
      mainTitle: '空间化框架页面'
    },
    menu: this.menus
  },

  style: {
    scrollEffectOpts: {
      enableScrollEffect: false,
      scrollEffectType:
        ScrollEffectType.GRADIENT_BLUR
    },

    systemMaterialEffect: {
      materialType:
        hdsMaterial.MaterialType.ADAPTIVE,

      materialLevel:
        this.currentMaterialLevel
    }
  },

  avoidLayoutSafeArea: false,
  enableComponentSafeArea: false
})

这里需要注意一个范围。systemMaterialEffect 主要配置标题栏按钮的沉浸光感,标题栏本身还有自己的背景与模糊能力。我们需要把按钮材质、模糊背板和滚动效果分成了不同的处理层。

所以页面不需要为了材质效果继续在外层补很多模糊和背景。

HdsTabs 的悬浮样式有三个基础条件

底部页签要进入悬浮布局,需要:

text 复制代码
barPosition = End
vertical = false
barOverlap = true

也就是页签位于底部、使用横向布局,并且让 TabBar 叠加在 TabContent 上方。当前悬浮页签指南明确要求这组条件。

基础结构可以写成:

ts 复制代码
HdsTabs({
  controller: this.tabsController
}) {
  // TabContent
}
.barOverlap(true)
.barPosition(BarPosition.End)
.vertical(false)

随后通过 barFloatingStyle 配置悬浮区域:

ts 复制代码
.barFloatingStyle({
  barWidth: {
    smallWidth: 200,
    mediumWidth: 300,
    largeWidth: 400
  },

  barBottomMargin: 28,

  gradientMask: {
    maskColor: '#66F1F3F5',
    maskHeight: 92
  },

  systemMaterialEffect: {
    materialType:
      hdsMaterial.MaterialType.ADAPTIVE,

    materialLevel:
      this.currentMaterialLevel
  }
})

smallWidthmediumWidthlargeWidth 可以给不同窗口宽度提供不同的页签栏尺寸。华为当前的悬浮页签示例同样使用了 200、300、400 三档宽度。

这一点我比较喜欢。只有三个一级入口时,大屏页面没有必要让底栏一直铺满整个窗口。内容区可以变宽,底部操作仍然保持相对集中的宽度,平板和折叠屏上会更舒服。

MiniBar 和悬浮页签共用底部空间

MiniBar 从 6.1.0(23)开始提供,它属于悬浮页签新增的自定义区域,与页签栏等高并水平对齐,同时支持展开和折叠两种样式。

barFloatingStyle 中加入:

ts 复制代码
miniBar: {
  miniBarBuilder: () =>
    this.miniBarBuilder()
}

就可以把自定义区域放到页签旁边。

我们的当前实验采用轻量结构:

ts 复制代码
@Builder
private miniBarBuilder() {
  Row({ space: 8 }) {
    Column()
      .width(36)
      .height(36)
      .borderRadius(18)
      .backgroundColor('#5065E8')

    Column({ space: 2 }) {
      Text('沉浸播放')
        .fontSize(12)
        .fontWeight(FontWeight.Medium)

      Text('MiniBar')
        .fontSize(10)
        .fontColor('#68708A')
    }
    .layoutWeight(1)
    .alignItems(HorizontalAlign.Start)

    Image(
      $r('sys.media.ohos_ic_public_pause')
    )
      .width(28)
      .height(28)
  }
  .height(56)
  .padding({
    left: 8,
    right: 8
  })
}

MiniBar 的空间并不大,所以我会控制里面的信息量。

音乐播放可以留下标题和暂停。

文件下载可以留下文件名、进度和暂停。

录音可以留下时长和停止。

后台任务可以留下当前状态和终止操作。

如果 MiniBar 已经需要放三四个按钮、多行文字和完整进度详情,页面结构可能需要重新考虑。Sheet 或独立页面通常更适合承载复杂任务。

页面到这里已经能够把标题栏、页签和 MiniBar 连起来。剩下的问题,就是现有项目有没有必要使用这套框架。

三、现有项目先看页面结构,再决定要不要接 HDS

HDS 的能力很多,但我不会因为页面需要沉浸材质,就直接替换现有导航。

普通卡片和搜索框的材质需求,继续使用 ArkUI 的 uiMaterial 已经足够。HDS 更适合标题栏、底部导航、MiniBar 和多设备框架一起发生变化的页面。

只改一个普通组件,继续使用 ArkUI

例如:

text 复制代码
搜索框
工具栏
悬浮卡片
普通 Popup

继续采用:

text 复制代码
ImmersiveMaterial
+
systemMaterial

就可以完成接入。

这类改动范围小,没必要动整张页面的导航结构。

标题栏和底部导航准备一起调整时,再考虑 HDS

如果页面同时需要:

  • 标题栏按钮沉浸材质
  • 标题栏模糊和滚动联动
  • 底部悬浮页签
  • 不同窗口宽度的页签尺寸
  • MiniBar
  • HDS 材质等级管理

这时 HdsNavigation + HdsTabs 的组合会更顺。

材质配置也能统一到:

text 复制代码
MaterialType
+
MaterialLevel

而不需要在多组普通组件之间分别维护不同的材质对象。

MiniBar 最好对应一个持续存在的状态

我觉得 MiniBar 最容易被滥用。

它长得像一块很有表现力的小组件,于是很容易什么都想往里面放。

对我来说,一个简单判断就够了:

这个状态离开当前页签以后,还需要继续看见吗?

音乐播放需要。

下载任务需要。

录音需要。

进行中的后台任务也可能需要。

普通页面快捷操作就未必需要。

MiniBar 的存在最好来自持续状态,而不是为了让底部导航显得更丰富。

材质等级优先从 ADAPTIVE 开始

HDS 当前推荐默认使用 ADAPTIVE,系统会根据设备性能动态调整材质等级。

所以我会先用:

text 复制代码
MaterialType.ADAPTIVE
MaterialLevel.ADAPTIVE

把页面结构跑稳定。

后面确实需要固定等级时,再调用 getSystemMaterialTypes() 看设备能力。

这样顺序会更轻:

text 复制代码
先完成 HdsNavigation
↓
再完成 HdsTabs
↓
开启悬浮页签
↓
加入 MiniBar
↓
使用 ADAPTIVE 材质
↓
最后考虑手动 MaterialLevel

页面里的问题也更容易定位。

标题栏有问题,就先看 Navigation。

页签布局不合适,就先看 HdsTabs 和 barFloatingStyle

MiniBar 太拥挤,就回到它自己的 Builder。

材质效果和性能再单独看 hdsMaterial

我更喜欢这种逐层调整的方式。HDS 本身已经承担了不少框架逻辑,页面外围再叠很多自定义布局,反而会把组件原本提供的能力重新拆散。

总结

HdsNavigationHdsTabs 和 MiniBar 放进同一张页面以后,HDS 的使用边界会清楚不少。

标题栏属于 HdsNavigation,它的按钮材质通过 titleBar.style.systemMaterialEffect 配置。底部悬浮页签属于 HdsTabs,需要满足底部位置、横向布局和 barOverlap=true,再通过 barFloatingStyle.systemMaterialEffect 配置材质。MiniBar 则作为悬浮页签旁边的自定义区域,适合保留播放、下载、录音等持续状态。

HDS 的材质选择也有自己的路径。

MaterialType 处理材质类型,MaterialLevel 处理显示等级。正常页面可以先采用 ADAPTIVE + ADAPTIVE,让系统按照当前设备调整;需要手动决定等级时,再通过 getSystemMaterialTypes() 查询能力。支持 IMMERSIVE 时可以考虑 EXQUISITEGENTLE,没有支持时则建议使用 SMOOTH

我会把 HDS 更多地用在页面框架改造上。只给一个普通组件加材质,没有必要扩大改动范围;标题栏、底部导航、MiniBar 和窗口适配准备一起调整时,再接入 HDS 会更合适。

当前页面先在 HarmonyOS 7 模拟器中检查接口、布局和基础交互。正式用于项目之前,大家仍应优先在具备权限的真机上检查标题栏按钮材质、底部悬浮页签、MiniBar,以及折叠屏和平板等不同窗口宽度下的页面表现。

完整代码

Main.ets

ts 复制代码
/**
 * HarmonyOS 7 沉浸光感深度实战 08
 *
 * 验证环境:
 * HarmonyOS SDK API 26
 * HarmonyOS 7 模拟器
 */

import {
  HdsNavigation,
  HdsNavigationTitleMode,
  HdsTabs,
  HdsTabsController,
  HdsNavigationMenuContentOptions,
  ScrollEffectType,
  hdsMaterial
} from '@kit.UIDesignKit';

import { BusinessError } from '@kit.BasicServicesKit';

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

  private mainScroller: Scroller =
    new Scroller();

  @State private materialTypesText: string =
    '尚未查询';

  @State private supportsImmersive: boolean =
    false;

  @State private currentMaterialLevel:
    hdsMaterial.MaterialLevel =
      hdsMaterial.MaterialLevel.ADAPTIVE;

  @State private currentLevelText: string =
    'ADAPTIVE';

  @State private strategyText: string =
    '系统根据设备性能选择材质等级';

  /**
   * 标题栏右侧的三个功能入口。
   */
  private menus:
    HdsNavigationMenuContentOptions = {
      value: [
        {
          content: {
            label: '编辑',
            icon:
              $r('sys.symbol.square_and_pencil')
          }
        },
        {
          content: {
            label: '收藏',
            icon:
              $r('sys.symbol.star')
          }
        },
        {
          content: {
            label: '更多',
            icon:
              $r('sys.symbol.more')
          }
        }
      ]
    };

  aboutToAppear(): void {
    this.loadMaterialCapability();
  }

  /**
   * 查询当前环境支持的 HDS 材质类型。
   */
  private loadMaterialCapability(): void {
    try {
      const types:
        Array<hdsMaterial.MaterialType> =
          hdsMaterial.getSystemMaterialTypes();

      this.supportsImmersive =
        types.indexOf(
          hdsMaterial.MaterialType.IMMERSIVE
        ) >= 0;

      this.materialTypesText =
        this.getMaterialTypeText(types);
    } catch (error) {
      const businessError =
        error as BusinessError;

      this.materialTypesText =
        `查询失败 ${businessError.code} `
          + `${businessError.message}`;

      this.supportsImmersive = false;
    }
  }

  /**
   * 将 MaterialType 转换为页面文字。
   */
  private getMaterialTypeText(
    types: Array<hdsMaterial.MaterialType>
  ): string {
    if (types.length === 0) {
      return '当前环境未返回 HDS 材质类型';
    }

    const names: Array<string> = [];

    for (
      let index: number = 0;
      index < types.length;
      index++
    ) {
      const type:
        hdsMaterial.MaterialType =
          types[index];

      switch (type) {
        case hdsMaterial.MaterialType.NONE:
          names.push('NONE');
          break;

        case hdsMaterial.MaterialType.ADAPTIVE:
          names.push('ADAPTIVE');
          break;

        case hdsMaterial.MaterialType.IMMERSIVE:
          names.push('IMMERSIVE');
          break;

        default:
          names.push(`UNKNOWN(${type})`);
          break;
      }
    }

    return names.join('、');
  }

  /**
   * 回到系统自适应等级。
   */
  private applyAdaptiveLevel(): void {
    this.currentMaterialLevel =
      hdsMaterial.MaterialLevel.ADAPTIVE;

    this.currentLevelText =
      'ADAPTIVE';

    this.strategyText =
      '系统根据设备性能选择材质等级';
  }

  /**
   * 按当前材质查询结果选择实验等级。
   */
  private applyCapabilityLevel(): void {
    if (this.supportsImmersive) {
      this.currentMaterialLevel =
        hdsMaterial.MaterialLevel.GENTLE;

      this.currentLevelText =
        'GENTLE';

      this.strategyText =
        '当前环境支持 IMMERSIVE,使用 GENTLE';

      return;
    }

    this.currentMaterialLevel =
      hdsMaterial.MaterialLevel.SMOOTH;

    this.currentLevelText =
      'SMOOTH';

    this.strategyText =
      '当前环境未确认 IMMERSIVE,使用 SMOOTH';
  }

  /**
   * MiniBar 保留状态、名称和一个高频操作。
   */
  @Builder
  private miniBarBuilder() {
    Row({ space: 8 }) {
      Column()
        .width(36)
        .height(36)
        .borderRadius(18)
        .backgroundColor('#5065E8')

      Column({ space: 2 }) {
        Text('沉浸播放')
          .fontSize(12)
          .fontWeight(FontWeight.Medium)
          .fontColor('#17203A')
          .maxLines(1)

        Text('MiniBar')
          .fontSize(10)
          .fontColor('#68708A')
          .maxLines(1)
      }
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start)

      Image(
        $r('sys.media.ohos_ic_public_pause')
      )
        .width(28)
        .height(28)
    }
    .height(56)
    .padding({
      left: 8,
      right: 8
    })
    .alignItems(VerticalAlign.Center)
  }

  /**
   * HDS 材质状态。
   */
  @Builder
  private materialInfoPanel() {
    Column({ space: 10 }) {
      Row({ space: 12 }) {
        Text('HDS MaterialType')
          .width('38%')
          .fontSize(13)
          .fontColor('#68708A')

        Text(this.materialTypesText)
          .layoutWeight(1)
          .fontSize(13)
          .fontWeight(FontWeight.Medium)
          .fontColor('#17203A')
          .textAlign(TextAlign.End)
          .maxLines(3)
      }
      .width('100%')

      Divider()
        .color('#E8EBF2')

      Row({ space: 12 }) {
        Text('MaterialLevel')
          .width('38%')
          .fontSize(13)
          .fontColor('#68708A')

        Text(this.currentLevelText)
          .layoutWeight(1)
          .fontSize(13)
          .fontWeight(FontWeight.Medium)
          .fontColor('#5065E8')
          .textAlign(TextAlign.End)
      }
      .width('100%')

      Text(this.strategyText)
        .fontSize(12)
        .fontColor('#68708A')
        .lineHeight(18)
        .width('100%')

      Row({ space: 10 }) {
        Button('系统自适应')
          .layoutWeight(1)
          .height(38)
          .fontSize(12)
          .fontColor(
            this.currentLevelText === 'ADAPTIVE'
              ? Color.White
              : '#5065E8'
          )
          .backgroundColor(
            this.currentLevelText === 'ADAPTIVE'
              ? '#5065E8'
              : '#EEF1FF'
          )
          .onClick(() => {
            this.applyAdaptiveLevel();
          })

        Button('按设备结果')
          .layoutWeight(1)
          .height(38)
          .fontSize(12)
          .fontColor(
            this.currentLevelText !== 'ADAPTIVE'
              ? Color.White
              : '#5065E8'
          )
          .backgroundColor(
            this.currentLevelText !== 'ADAPTIVE'
              ? '#5065E8'
              : '#EEF1FF'
          )
          .onClick(() => {
            this.applyCapabilityLevel();
          })
      }
      .width('100%')
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#EEFFFFFF')
    .borderRadius(20)
  }

  /**
   * 首页内容使用 Scroll,
   * 同时保留给 HdsNavigation 的滚动绑定。
   */
  @Builder
  private homeContent() {
    Scroll(this.mainScroller) {
      Column({ space: 12 }) {
        this.materialInfoPanel()

        ForEach(
          [1, 2, 3, 4, 5, 6],
          (item: number) => {
            Column({ space: 6 }) {
              Text(`内容区域 ${item}`)
                .fontSize(17)
                .fontWeight(FontWeight.Bold)
                .fontColor('#17203A')
                .width('100%')

              Text(
                '滚动页面,观察内容与标题栏、'
                  + '悬浮页签之间的层级关系。'
              )
                .fontSize(13)
                .fontColor('#68708A')
                .lineHeight(20)
                .width('100%')
            }
            .width('100%')
            .height(116)
            .padding(16)
            .justifyContent(FlexAlign.Center)
            .alignItems(HorizontalAlign.Start)
            .backgroundColor(Color.White)
            .borderRadius(20)
          },
          (item: number) =>
            item.toString()
        )
      }
      .width('100%')
      .padding({
        left: 20,
        right: 20,
        top: 16,
        bottom: 150
      })
    }
    .width('100%')
    .height('100%')
    .scrollBar(BarState.Off)
  }

  @Builder
  private discoveryContent() {
    Column({ space: 12 }) {
      Text('发现')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .fontColor('#17203A')

      Text('观察页签切换与悬浮底栏')
        .fontSize(14)
        .fontColor('#68708A')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }

  @Builder
  private profileContent() {
    Column({ space: 12 }) {
      Text('我的')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .fontColor('#17203A')

      Text('MiniBar 与页签栏保持在内容上方')
        .fontSize(14)
        .fontColor('#68708A')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }

  build() {
    HdsNavigation() {
      HdsTabs({
        controller: this.tabsController
      }) {
        TabContent() {
          this.homeContent()
        }
        .tabBar(
          new BottomTabBarStyle(
            $r('sys.media.ohos_ic_public_clock'),
            '首页'
          )
        )

        TabContent() {
          this.discoveryContent()
        }
        .tabBar(
          new BottomTabBarStyle(
            $r('sys.media.wifi_router_fill'),
            '发现'
          )
        )

        TabContent() {
          this.profileContent()
        }
        .tabBar(
          new BottomTabBarStyle(
            $r('sys.media.ohos_ic_public_clock'),
            '我的'
          )
        )
      }
      .barOverlap(true)
      .barPosition(BarPosition.End)
      .vertical(false)
      .barFloatingStyle({
        barWidth: {
          smallWidth: 200,
          mediumWidth: 300,
          largeWidth: 400
        },

        barBottomMargin: 28,

        gradientMask: {
          maskColor: '#66F1F3F5',
          maskHeight: 92
        },

        systemMaterialEffect: {
          materialType:
            hdsMaterial.MaterialType.ADAPTIVE,

          materialLevel:
            this.currentMaterialLevel
        },

        miniBar: {
          miniBarBuilder: () =>
            this.miniBarBuilder()
        }
      })
    }
    .mode(NavigationMode.Stack)
    .titleBar({
      content: {
        title: {
          mainTitle: '空间化框架页面'
        },

        menu: this.menus
      },

      style: {
        scrollEffectOpts: {
          enableScrollEffect: false,

          scrollEffectType:
            ScrollEffectType.GRADIENT_BLUR
        },

        systemMaterialEffect: {
          materialType:
            hdsMaterial.MaterialType.ADAPTIVE,

          materialLevel:
            this.currentMaterialLevel
        }
      },

      avoidLayoutSafeArea: false,
      enableComponentSafeArea: false
    })
    .bindToScrollable([
      this.mainScroller
    ])
    .hideBackButton(true)
    .titleMode(
      HdsNavigationTitleMode.MINI
    )
    .width('100%')
    .height('100%')
    .backgroundColor('#F4F6FB')
  }
}
相关推荐
yuhulkjv3357 小时前
Gemini鸿蒙版导出word格式的终极解法:AI 导出鸭如何重构AI内容落地链路
人工智能·ai·word·harmonyos·ai导出鸭
whyutianict_vv10 小时前
从 Web 前端到 HarmonyOS ArkTS:一次 AI 鸿蒙全栈智能体开发的迁移实录
前端·人工智能·harmonyos
m0_7496902310 小时前
【寻迹校园 HarmonyOS NEXT 实战 01】从校园痛点到可上架 MVP:失物招领应用产品设计
人工智能·深度学习·移动开发·harmonyos·arkts·arkui·产品设计
m0_7496902310 小时前
【寻迹校园 HarmonyOS NEXT 实战 03】NavPathStack 路由实战:18 个页面如何集中管理
华为·移动开发·harmonyos·arkui·navigation·navpathstack
m0_7496902311 小时前
【寻迹校园 HarmonyOS NEXT 实战 02】多模块工程拆解:entry、HAR 与 HSP 如何分工
华为·harmonyos·arkts·软件架构·har·hsp
用户09340777351412 小时前
HarmonyOS WPS Open SDK 实践:用 SdkConstants 判断当前 HAR 形态
harmonyos
独守一片天13 小时前
HarmonyOS鸿蒙新生态智能体意图框架怎么设计?
华为·harmonyos
梦想不只是梦与想1 天前
鸿蒙应用api的兼容性:参数配置(二)
harmonyos·sdk版本·sdkversion
北墨NoLimit1 天前
鸿蒙线程间通信怎么选:TaskPool、TaskGroup、LongTask 与 Worker 实战
typescript·harmonyos
woshihuanglaoshi1 天前
错题四科入库:鸿蒙错题本种子数据与复习队列效果
学习·华为·harmonyos·鸿蒙