《HarmonyOS底部页签-沉浸光感组件实战》模糊样式:打造毛玻璃效果

HarmonyOS 底部页签 · 沉浸光感组件实战:模糊样式打造毛玻璃效果

开篇:一个容易被忽略的 API 限制

HarmonyOS NEXT 开发中,HdsTabs 的模糊样式是很多人想用的功能,但实际落地时经常出现"效果出不来"或者"跟预期完全不一样"的情况。原因在于:这个 API 有严格的依赖条件,而且和行为和原生 Tabs 的属性存在冲突

官方文档虽然给出了示例,但没有解释清楚"为什么必须这样设置"以及"不同属性之间是如何互相影响的"。这篇文章从源码行为出发,讲清楚模糊样式的两种实现方式,以及实际开发中必须注意的边界限制。

这个功能解决什么问题

HdsTabs 的模糊样式解决的问题很简单:让底部 TabBar 具备毛玻璃效果,同时保持对内容的可读性

实现方式 原理 适用场景
直接模糊 通过 barBackgroundBlurStyle 设置系统定义的模糊风格 快速实现标准毛玻璃效果
渐变模糊 通过 barBackgroundStyle 自定义遮罩颜色和高度 需要与背景色融合的视觉设计

从 6.0.0(20) 版本开始支持,6.0.2(22) 后不再需要手动导入 HdsTabsAttribute

环境说明

text 复制代码
DevEco Studio 版本:DevEco Studio 6.1.0 及以上
HarmonyOS SDK 版本:HarmonyOS 6.1.0(23) 及以上
目标设备:手机

核心实现:两种模糊效果

示例一:直接模糊

直接模糊使用 barBackgroundBlurStyle 属性,设置 BlurStyle 枚举值来控制模糊程度。

typescript 复制代码
import { HdsTabs, HdsTabsAttribute, HdsTabsController } from '@kit.UIDesignKit';

@Entry
@Component
struct DirectBlurDemo {
  private controller: HdsTabsController = new HdsTabsController();

  build() {
    Column() {
      HdsTabs({ controller: this.controller }) {
        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Pink)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '页签1' })

        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Blue)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '页签2' })
      }
      .barOverlap(true)                    // 关键:TabBar 叠加在 TabContent 之上
      .barPosition(BarPosition.End)        // 关键:必须位于底部
      .vertical(false)                     // 关键:必须水平排列
      .barBackgroundBlurStyle(BlurStyle.NONE)  // 设置为 NONE 时,系统默认的模糊效果不生效
      // 如果直接写 .barBackgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK)
      // 系统默认模糊会被替换为自定义模糊
    }
    .width('100%')
    .height('100%')
  }
}

这里需要特别说明:官方文档提到"去掉TabBar节点,barBackgroundBlurStyle默认设置的模糊的属性值为BlurStyle.NONE",这个描述容易让人误解。实际行为是:

  • 如果显式设置 barBackgroundBlurStyle 为某个值,系统默认的毛玻璃效果会被这个值替代
  • 如果想让毛玻璃完全不生效,必须显式设置为 BlurStyle.NONE
  • 这个设计有点反直觉,因为大多数开发者会认为不设置就默认没有模糊效果

示例二:渐变模糊

渐变模糊通过 barBackgroundStyle 实现,可以自定义遮罩的颜色和高度。

typescript 复制代码
import { HdsTabs, HdsTabsAttribute, HdsTabsController } from '@kit.UIDesignKit';

@Entry
@Component
struct GradientBlurDemo {
  private controller: HdsTabsController = new HdsTabsController();

  build() {
    Column() {
      HdsTabs({ controller: this.controller }) {
        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Pink)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '页签1' })

        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Blue)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '页签2' })
      }
      .barOverlap(true)
      .barPosition(BarPosition.End)
      .vertical(false)
      .barBackgroundStyle({
        maskColor: Color.Yellow,  // 遮罩颜色,可以根据 UI 设计图调整
        maskHeight: 80            // 模糊区域高度,单位 vp
      })
    }
    .width('100%')
    .height('100%')
  }
}

渐变模糊的原理是:通过 maskColor 定义一个颜色遮罩,maskHeight 控制这个遮罩从底部向上的高度。实际效果是底部纯色,向上逐渐透明,同时叠加模糊效果。

约束条件的底层逻辑

这三个条件缺一不可:

  1. barPosition 必须为 BarPosition.End:HdsTabs 的模糊效果只支持底部 TabBar,如果改为顶部或者侧边,渲染管线会直接跳过模糊处理逻辑

  2. barOverlap 必须为 true :毛玻璃效果依赖于 TabBar 和内容区域的叠加关系。如果 barOverlapfalse,TabBar 会独立占据一个区域,模糊效果无法正确渲染

  3. vertical 必须为 false:水平排列的 TabBar 才能触发底部模糊逻辑

这三个条件的组合是框架层面的约束,修改任意一个都会导致 API 调用被忽略。实测发现,即使代码编译通过,运行时也不会有任何错误提示------效果不生效也不报错,这个问题在调试时比较难发现。

常见问题:与原生 Tabs 属性的冲突

这是开发中最容易踩的坑,官方文档明确提到了三种冲突情况:

冲突 1:barBackgroundBlurStyle

如果通过原生 TabsbarBackgroundBlurStyle 属性设置模糊,HdsTabs 的默认模糊效果会完全失效。

typescript 复制代码
// 错误写法:混合使用
HdsTabs({ controller: this.controller }) {
  // ...
}
.barBackgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK)  // 原生属性会覆盖 HdsTabs 的默认模糊

原因:HdsTabs 内部有自己的模糊渲染管线,原生 Tabs 属性设置后会替换这个管线。

冲突 2:barBackgroundEffect

typescript 复制代码
// 同样会导致 HdsTabs 默认模糊失效
HdsTabs({ controller: this.controller }) {
  // ...
}
.barBackgroundEffect(new BlurEffect())  // 原生属性冲突

冲突 3:barBackgroundColor

这个冲突比较隐蔽:只有模糊半径会生效(固定 80vp),颜色不会生效。

typescript 复制代码
// 设置了背景色,但模糊效果只有半径生效
HdsTabs({ controller: this.controller }) {
  // ...
}
.barBackgroundColor(Color.Red)  // 颜色会被忽略,模糊半径 80vp 生效

实际开发建议不要混合使用 HdsTabs 的模糊属性和原生 Tabs 的模糊属性 。如果需要在 HdsTabs 上实现毛玻璃效果,统一使用 HdsTabs 提供的 barBackgroundStylebarBackgroundBlurStyle

最佳实践

  1. 统一使用 HdsTabs 的属性 :不要在 HdsTabs 组件上混用原生 Tabs 的属性设置模糊效果。如果确定使用 HdsTabs,所有模糊相关设置都通过 HdsTabs 的 API 完成

  2. maskHeight 的取值参考设备高度maskHeight 单位是 vp,常见的取值在 60-120vp 之间。取值过小会导致模糊区域太窄,视觉效果不明显;取值过大会让 TabBar 看起来像是被"淹没"在半透明区域中。建议根据 UI 设计稿的 TabBar 实际高度来确定

  3. maskColor 优先使用 Color 枚举或色值maskColor 支持 ResourceColor 类型,但实测使用 $r() 资源引用时,在某些版本上会出现颜色解析失败的问题。推荐直接使用 Color 枚举或十六进制色值

  4. 验证约束条件 :在 UI 测试时,建议先单独检查 barOverlapbarPosition 是否正确设置。可以在 aboutToAppear() 中加入日志验证:

typescript 复制代码
aboutToAppear() {
  console.log('HdsTabs barOverlap 检查')
  // 如果效果不生效,优先检查这三个条件
}

Demo 入口

合并两种实现方式,方便快速验证:

typescript 复制代码
@Entry
@Component
struct HdsTabsBlurDemo {
  private controller: HdsTabsController = new HdsTabsController();
  @State private useGradient: boolean = false;

  build() {
    Column() {
      Button(this.useGradient ? '切换为直接模糊' : '切换为渐变模糊')
        .onClick(() => {
          this.useGradient = !this.useGradient;
        })

      HdsTabs({ controller: this.controller }) {
        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Pink)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '首页' })

        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Blue)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '发现' })

        TabContent() {
          Column().width('100%').height('100%').backgroundColor(Color.Orange)
        }
        .tabBar({ icon: $r('app.media.startIcon'), text: '我的' })
      }
      .barOverlap(true)
      .barPosition(BarPosition.End)
      .vertical(false)
      .barBackgroundStyle(this.useGradient
        ? { maskColor: Color.Yellow, maskHeight: 80 }
        : undefined)
      .barBackgroundBlurStyle(this.useGradient
        ? BlurStyle.NONE
        : BlurStyle.COMPONENT_ULTRA_THICK)
    }
    .width('100%')
    .height('100%')
  }
}

FAQ

Q:为什么设置了约束条件,毛玻璃效果还是不生效?

A:检查是否混用了原生 Tabs 的属性。如果写入了 barBackgroundColorbarBackgroundEffect 或原生 barBackgroundBlurStyle,HdsTabs 默认的毛玻璃效果会被覆盖。建议先去掉所有原生 Tabs 的模糊相关属性再测试。

Q:barBackgroundStylemaskHeight 单位是什么?支持变量动态修改吗?

A:单位是 vp,支持通过 @State 变量动态修改。但注意:修改后不会触发 TabBar 的重定位,只是模糊区域的范围变化。如果需要配合动画,建议使用 animateTo() 进行过渡。

Q:为什么设置了 barBackgroundColor 后,模糊半径变成了 80vp?

A:这是 HdsTabs 的默认行为。当检测到原生 barBackgroundColor 属性设置后,HdsTabs 会回退到一套默认的模糊处理逻辑:固定模糊半径 80vp,颜色不生效。这种设计是为了保持兼容性,但实际开发中不建议依赖这个行为------因为 80vp 的模糊半径无法自定义,且效果不稳定。

相关推荐
大雷神8 小时前
第26篇|单摄预览会话:CameraInput、PreviewOutput、PhotoSession 的关系
harmonyos
博客-小覃13 小时前
Zabbix之华为交换机的日志记录信息操作详细教程
服务器·网络·华为·zabbix
不羁的木木16 小时前
Form Kit(卡片开发服务)学习笔记01-核心概念与架构设计
笔记·学习·harmonyos
不羁的木木16 小时前
ArkWeb实战学习笔记01-核心概念与架构设计
笔记·学习·harmonyos
Goway_Hui17 小时前
【鸿蒙原生应用开发--ArkUI--010】Recipe-app 菜谱应用开发教程
华为·harmonyos
●VON17 小时前
鸿蒙 BodyAR 实战:基于人体骨骼追踪的体感运动计数器开发全解
华为·ar·harmonyos·鸿蒙·新特性
Davina_yu17 小时前
页面路由导航:Router与Navigation组件的跳转传参(7)
harmonyos·鸿蒙·鸿蒙系统
Ww.xh18 小时前
鸿蒙WebView IPC防伪造请求方案
华为·harmonyos
大雷神19 小时前
第25篇|Surface 预览控制:ArkUI 页面如何接住相机画面
harmonyos