在这里插入图片描述

在这里插入图片描述

一、引言

毛玻璃效果(Glassmorphism / Frosted Glass)是近年来移动端和桌面端 UI 设计中非常流行的视觉风格。它通过半透明背景配合高斯模糊,营造出"透过磨砂玻璃观看后方内容"的质感,兼具层次感与高级感。

在 HarmonyOS NEXT 6.1.1(API 24)中,ArkUI 框架提供了原生的 .blur() 高斯模糊 API 和 backgroundBlurStyle 系统级模糊样式,使得在鸿蒙应用中实现毛玻璃效果变得简单高效。本文将以一个完整的示例应用为线索,深入讲解如何使用 Column + blur + backgroundColor 这三大核心技术,构建纵向层叠的毛玻璃卡片布局。

我们将从最基础的布局原理开始,逐步深入到每个 API 的细节用法、参数调优技巧、性能优化方案以及多种实际场景的扩展实践。无论你是刚接触鸿蒙开发的初学者,还是希望提升 UI 质感的中级开发者,这篇文章都能为你提供全面、可落地的技术指导。


二、项目背景与效果预览

2.1 什么是毛玻璃效果

毛玻璃效果的核心视觉特征是:

特征 描述 实现方式
半透明背景 内容透过半透明层显示,产生层次感 backgroundColor + alpha 通道
背景模糊 透过半透明层看到的内容被模糊处理 blur() API
玻璃边缘 半透明亮边框营造玻璃厚度感 border + rgba 高光色
悬浮阴影 卡片与背景之间产生空间距离 shadow 属性

2.2 示例应用的视觉效果

本文构建的示例应用呈现以下视觉效果:

  • 深色渐变背景:从深蓝黑(#0f0c29)到深紫蓝(#302b63)再到深紫(#24243e)的纵向渐变,为毛玻璃提供丰富的视觉底层
  • 装饰光晕:使用粉色和蓝色圆形元素配合大模糊值(blur(80)、blur(60))模拟发光效果,增强背景层次
  • 四张毛玻璃卡片:每张卡片以 Column 布局承载内容,使用半透明白色底色 + blur(20) + 半透明边框,呈现典型的毛玻璃质感
  • 阶梯层叠:卡片之间通过 position 偏移(每张向下 16vp)形成纵向层叠,类似卡片堆叠的视觉效果
  • 入场动画:卡片从下方滑入并渐显,提升用户体验

2.3 适用场景

这种布局非常适合以下场景:

  • 音乐播放器的播放列表 / 专辑封面展示
  • 个人中心页面的信息卡片
  • 系统设置面板的选项分组
  • 数据看板的指标卡片
  • 社交应用的用户资料卡片
  • 任何需要突出层次感和高级感的 UI 界面

三、开发环境准备

3.1 环境要求

在开始编码之前,请确保开发环境满足以下要求:

项目 要求
操作系统 Windows 10/11 64 位
IDE DevEco Studio 5.0 及以上版本
SDK HarmonyOS NEXT 6.1.1(API 24)
构建工具 hvigor(内置在 DevEco Studio 中)
目标设备 鸿蒙手机 / 平板 / 模拟器

3.2 创建项目

在 DevEco Studio 中创建一个新的 Empty Ability 项目:

  1. 打开 DevEco Studio,点击 “Create Project”
  2. 选择 “Empty Ability” 模板
  3. 配置项目名称(如 MyApplication)
  4. 确保 Compile SDK 选择 API 24(HarmonyOS NEXT 6.1.1)
  5. 点击 Finish 完成创建

3.3 项目结构概览

创建完成后,项目的核心结构如下:

MyApplication/
├── entry/
│   └── src/
│       └── main/
│           ├── ets/
│           │   ├── entryability/
│           │   │   └── EntryAbility.ets      # 应用入口 Ability
│           │   └── pages/
│           │       └── BlurColumnPage.ets    # 毛玻璃布局页面(我们即将创建)
│           ├── resources/
│           │   └── base/
│           │       ├── element/              # 颜色、字符串等资源
│           │       ├── media/                # 图片资源
│           │       └── profile/
│           │           └── main_pages.json   # 页面路由配置
│           └── module.json5                  # 模块配置
├── build-profile.json5                       # 项目构建配置
└── oh-package.json5                          # 依赖管理

3.4 配置页面路由

entry/src/main/resources/base/profile/main_pages.json 中注册页面路由:

{
  "src": [
    "pages/BlurColumnPage"
  ]
}

3.5 设置应用入口

EntryAbility.ets 中,将 windowStage.loadContent() 的路径指向我们的新页面:

// entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

export default class EntryAbility extends UIAbility {
  // ... 其他生命周期方法省略

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(0x0000, 'MyApp', 'Ability onWindowStageCreate');
    windowStage.loadContent('pages/BlurColumnPage', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'MyApp',
          'Failed to load content: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(0x0000, 'MyApp', 'Succeeded in loading content.');
    });
  }
}

至此,环境准备完成。下面我们进入核心技术的学习。


四、核心技术深度解析

4.1 Column 容器布局原理

Column 是 ArkUI 中最基础的布局容器之一,它的主轴(Main Axis)方向为垂直方向,交叉轴(Cross Axis)方向为水平方向。

4.1.1 Column 的坐标系统

理解 Column 的坐标系统是掌握布局的基础:

      ┌─────────────────────────┐
      │        交叉轴            │
      │    ←──────────────→     │
      │  ┌───────┐  ┌───────┐  │  ↑
      │  │ 子组件  │  │ 子组件  │  │  │
      │  │   A    │  │   B    │  │  主
      │  └───────┘  └───────┘  │  轴
      │  ┌──────────────────┐  │  │
      │  │    子组件 C       │  │  │
      │  └──────────────────┘  │  ↓
      └─────────────────────────┘
4.1.2 主轴控制:justifyContent

justifyContent 控制子组件在主轴(垂直方向)上的排列方式:

Column() {
  // 子组件...
}
.justifyContent(FlexAlign.Start)   // 顶部起始排列
// .justifyContent(FlexAlign.Center) // 居中对齐
// .justifyContent(FlexAlign.End)    // 底部对齐
// .justifyContent(FlexAlign.SpaceBetween) // 均匀分布,首尾靠边
4.1.3 交叉轴控制:alignItems

alignItems 控制子组件在交叉轴(水平方向)上的对齐方式:

Column() {
  // 子组件...
}
.alignItems(HorizontalAlign.Start)  // 左对齐
// .alignItems(HorizontalAlign.Center) // 居中对齐
// .alignItems(HorizontalAlign.End)    // 右对齐
4.1.4 子组件在 Column 中的占位

在 Column 中,如果子组件没有显式设置宽度,默认会尝试撑满父容器的宽度(视子组件类型而定)。Text、Button 等组件默认自适应内容宽度,Column 自身默认撑满父容器宽度。

这个行为在毛玻璃卡片布局中很重要——我们通常希望卡片撑满可用宽度,所以会给 Column 显式设置 .width('100%')

4.2 blur() 高斯模糊 API 详解

.blur() 是 ArkUI 中用于对组件及其内容应用高斯模糊效果的 API。它是实现毛玻璃效果最核心的 API。

4.2.1 基本语法
Component()
  .blur(radius: number)

其中 radius 参数为模糊半径,单位是 vp(虚拟像素),取值范围通常为 0~100。数值越大,模糊效果越强烈。

4.2.2 模糊半径的视觉效果
模糊半径 视觉效果 适用场景
1~4 极轻微模糊,消除锯齿感 标签、小元素背景
5~15 中等模糊,可见纹理但内容模糊 毛玻璃卡片主体
16~30 强模糊,仅能感知颜色和光影 主要毛玻璃面板
31~60 极强模糊,仅剩色彩区域 光晕、装饰效果
60+ 几乎完全虚化,只剩颜色 背景光晕、氛围光
4.2.3 blur 的工作机制

理解 blur 的工作机制对于用好它至关重要:

  1. blur 是对组件自身内容及其背景的模糊:当对一个 Column 应用 .blur(20) 时,Column 内部所有子组件以及 Column 的 backgroundColor 都会被模糊处理

  2. blur 与 backgroundColor 的协同:如果 Column 的 backgroundColor 是纯色(alpha=1),模糊效果只能模糊内部的子组件;如果 backgroundColor 是半透明的(alpha<1),模糊效果会同时模糊透过半透明区域看到的父容器背景内容——这正是毛玻璃效果的实现原理

  3. blur 不影响子组件的交互:模糊是纯粹的视觉效果,不影响子组件的触摸事件和点击响应

4.2.4 backgroundBlurStyle 系统级模糊

除了 .blur() API,ArkUI 还提供了 backgroundBlurStyle 属性,用于快速应用系统级的背景模糊样式:

Component()
  .backgroundBlurStyle(BlurStyle.Thin)    // 轻薄模糊
  // .backgroundBlurStyle(BlurStyle.Regular) // 常规模糊
  // .backgroundBlurStyle(BlurStyle.Thick)   // 厚重模糊

backgroundBlurStyle.blur() 的区别在于:

对比维度 .blur() backgroundBlurStyle
控制粒度 精确到数值 系统预设的枚举值
灵活性 高,可精确调参 低,只有几种固定样式
使用简便性 需手动配半透明底色 自动处理背景样式
兼容性 API 6+ 通用 API 12+ 新增

在本文的示例中,我们使用 .blur() 以获得更精确的控制。

4.3 backgroundColor 与 alpha 通道

backgroundColor 配合 alpha 通道(透明度)是实现毛玻璃效果的另一关键。

4.3.1 rgba 颜色表示法

在 ArkTS 中,颜色可以使用多种表示法:

// 十六进制(不支持 alpha)
.backgroundColor('#ffffff')

// rgba 格式(支持 alpha,取值范围 0~1)
.backgroundColor('rgba(255, 255, 255, 0.12)')

// 十六进制 + alpha(8 位十六进制,前 6 位是 RGB,后 2 位是 alpha)
.backgroundColor('#1affffff')  // alpha = 0.10

其中 rgba 格式是最直观的,四个参数分别代表红、绿、蓝、透明度。透明度 alpha 取值范围 0(完全透明)到 1(完全不透明)。

4.3.2 毛玻璃中的 alpha 取值策略

alpha 值的选择直接影响毛玻璃的视觉效果:

alpha = 0.05 ~ 0.10  → 极淡,背景几乎完全透出,模糊感弱
alpha = 0.10 ~ 0.20  → 适中,背景清晰可见,模糊感明显 ✓ 推荐
alpha = 0.20 ~ 0.35  → 较浓,背景隐约可见,更像彩色玻璃
alpha = 0.35 ~ 0.50  → 浓厚,背景仅剩光影,倾向于纯色面板
alpha = 0.50+        → 不再有毛玻璃感,接近纯色不透明

对于大多数毛玻璃效果场景,alpha 值在 0.10~0.20 之间效果最佳。太低了玻璃感不足,太高了又失去了"透过玻璃看背景"的核心特征。

4.4 Stack 层叠容器

Stack 是 ArkUI 中用于实现层叠布局的容器,它的子组件按照添加顺序从下往上堆叠。

4.4.1 Stack 的基本使用
Stack() {
  // 先添加的组件在底层
  Column() { /* 背景层 */ }
    .width('100%')
    .height('100%')

  // 后添加的组件在上层
  Column() { /* 前景层 */ }
    .width('100%')
    .height('100%')
}

在毛玻璃布局中,Stack 的层叠特性是实现"背景透过前景显示"效果的基础架构。

4.4.2 Stack 的对齐方式

Stack 通过 alignContent 属性控制子组件在容器内的对齐方式:

Stack()
  .alignContent(Alignment.Center)     // 默认居中
  .alignContent(Alignment.TopStart)   // 左上角
  .alignContent(Alignment.BottomEnd)  // 右下角

4.5 综合:毛玻璃效果的技术原理

结合以上三个核心技术,毛玻璃效果的实现原理可以概括为:

┌── Stack 层叠容器 ──────────────────────────┐
│                                              │
│  [底层] 背景层                                │
│    ├── 渐变色 / 图片                          │
│    └── 装饰光晕                               │
│                                              │
│  [上层] 毛玻璃卡片                            │
│    ├── backgroundColor: rgba(白, 0.12)       │
│    │     ← 半透明底色, 让下方背景透过来        │
│    ├── blur(20)                              │
│    │     ← 模糊透过来的背景内容               │
│    └── border: rgba(白, 0.25)               │
│          ← 玻璃边缘高光                      │
│                                              │
│  视觉结果:透过磨砂玻璃看到模糊后的背景        │
│                                              │
└──────────────────────────────────────────────┘

核心公式毛玻璃效果 = Stack(背景) + Column(半透明底色 + blur + 边框)


五、完整代码实现

下面我们逐段构建完整的毛玻璃布局页面。建议在 DevEco Studio 中创建 BlurColumnPage.ets 文件并跟随编写。

5.1 数据模型定义

首先定义毛玻璃卡片的数据结构:

/**
 * 数据模型:毛玻璃卡片数据
 * icon  : 卡片图标(使用 Emoji 作为图标,无需图片资源)
 * title : 卡片标题
 * desc  : 卡片描述文字
 * tag   : 右上角标签
 */
interface GlassCardItem {
  icon: string;       // 图标(emoji)
  title: string;      // 标题
  desc: string;       // 描述内容
  tag: string;        // 标签
}

使用 interface 定义数据结构是 ArkTS 中的标准做法。这里我们使用 Emoji 作为图标,避免了对图片资源的外部依赖,使示例更加轻量。

5.2 毛玻璃卡片子组件(GlassCard)

这是整个布局的核心组件,实现了毛玻璃效果的三个关键技术点:

@Component
struct GlassCard {
  private item: GlassCardItem = { icon: '', title: '', desc: '', tag: '' };
  /** 层叠偏移量:越靠后的卡片偏移越大,营造纵深感 */
  private offsetY: number = 0;
  /** 卡片索引(用于渐变动画延迟等) */
  private index: number = 0;

  build() {
    // ── 最外层 Column:承载整张毛玻璃卡片 ──
    Column() {
      // ======== 第 1 行:图标 + 标题 + 标签(横向排列) ========
      Row() {
        // 图标区域:使用大号 Emoji 作为装饰
        Text(this.item.icon)
          .fontSize(28)
          .lineHeight(34)

        // 标题文字:白色粗体
        Text(this.item.title)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#ffffff')
          .lineHeight(26)
          .margin({ left: 10 })

        // 弹性空间:将标签推到行尾
        Blank()

        // 标签气泡:也带了毛玻璃效果(半透明背景 + 弱模糊)
        Text(this.item.tag)
          .fontSize(11)
          .fontColor('#ffffff')
          .fontWeight(FontWeight.Medium)
          .padding({ left: 10, right: 10, top: 3, bottom: 3 })
          .backgroundColor('#33ffffff')       // 半透明白色
          .borderRadius(20)                   // 圆角气泡
          .blur(2)                            // 微弱模糊
      }
      .alignItems(VerticalAlign.Center)
      .width('100%')

      // ======== 第 2 行:描述文字 ========
      Text(this.item.desc)
        .fontSize(14)
        .fontColor('#e0e6ff')                // 浅蓝白色,与深色背景协调
        .lineHeight(22)
        .margin({ top: 10 })
        .width('100%')
        .textAlign(TextAlign.Start)
    }
    // ==========================================================
    //  ★★★ 核心:毛玻璃(Frosted Glass)三要素 ★★★
    //    ① backgroundColor('rgba(255,255,255,0.12)') — 半透明底色
    //    ② .blur(20) — 高斯模糊,模拟玻璃透光效果
    //    ③ .border + rgba 亮边框 — 模拟玻璃边缘高光
    // ==========================================================
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .padding(18)

    // ── ① 半透明白色底色:透过背景显示下方内容 ──
    .backgroundColor('rgba(255, 255, 255, 0.12)')

    // ── ② 高斯模糊:使卡片背景呈现"毛玻璃"质感 ──
    .blur(20)

    // ── ③ 玻璃边缘高光边框 ──
    .border({
      width: 1,
      color: 'rgba(255, 255, 255, 0.25)',   // 半透明白色边框
      style: BorderStyle.Solid
    })

    // ── 其他视觉属性 ──
    .borderRadius(20)                        // 大圆角增强玻璃质感
    .shadow({
      radius: 20,                            // 大阴影半径,柔和扩散
      color: 'rgba(0, 0, 0, 0.3)',           // 黑色半透明阴影
      offsetX: 0,                            // 无水平偏移
      offsetY: 8                             // 垂直向下偏移,产生悬浮感
    })

    // ── 层叠偏移:每张卡片相对前一张偏移一定距离 ──
    .position({ top: this.offsetY })

    // ── 动画:页面加载时卡片从下方滑入 ──
    .transition({
      type: TransitionType.Insert,
      translate: { x: 0, y: 60 },           // 从下方 60vp 处开始
      opacity: 0,                             // 初始透明度为 0
      duration: 400,                          // 动画时长 400ms
      curve: Curve.Friction                   // 衰减曲线,自然减速
    })
  }
}
关键代码详解

第 96 行 — 半透明底色

.backgroundColor('rgba(255, 255, 255, 0.12)')

这里的 alpha 值 0.12 是经过调试选择的"黄金比例"。如果改为 0.06,卡片会太透明,背景几乎完全透出,毛玻璃感不足;如果改为 0.25,卡片又会太厚重,失去了轻盈感。

第 98 行 — 高斯模糊

.blur(20)

blur(20) 是中等偏强的模糊程度。在这个值下,透过半透明区域看到的背景图文会明显模糊,但又保留了大致的色彩和明暗分布,呈现出"透过磨砂玻璃"的视觉效果。

第 100~104 行 — 玻璃边缘高光

.border({
  width: 1,
  color: 'rgba(255, 255, 255, 0.25)',
  style: BorderStyle.Solid
})

厚度仅为 1vp 的半透明边框,模拟了真实玻璃的边缘高光。想象一下真实世界中的玻璃杯——边缘处的玻璃更厚,光线透过时会呈现出亮边。这个 1px 的边框就是在模拟这个物理现象。

第 115 行 — 层叠偏移

.position({ top: this.offsetY })

每个卡片实例通过 offsetY 参数在垂直方向产生不同的偏移量,从而实现阶梯式层叠效果。这个偏移量由父组件在 ForEach 循环中计算传入。

5.3 配置数据

在主页面组件中,我们定义四张卡片的数据:

private readonly cardList: GlassCardItem[] = [
  {
    icon: '🎵',
    title: '正在播放',
    desc: 'Blur — 毛玻璃效果让背景音乐封面透过卡片若隐若现',
    tag: 'NOW'
  },
  {
    icon: '📂',
    title: '最近项目',
    desc: '鸿蒙 ArkTS 示例:Column + Blur 层叠布局 · v1.0',
    tag: '3 个'
  },
  {
    icon: '⚙️',
    title: '系统设置',
    desc: '显示 · 声音 · 通知 · 隐私 · 所有设置项均采用毛玻璃面板',
    tag: '设置'
  },
  {
    icon: '📊',
    title: '数据看板',
    desc: 'CPU 45% · 内存 62% · 存储 128G/256G · 网络 正常',
    tag: '实时'
  }
];

四个数据项覆盖了音乐、文件、设置、数据仪表盘四种常见场景,代码复用性好,读者可以轻松替换为自己的业务数据。

5.4 主页面组件(BlurColumnPage)

主页面是整个布局的"导演",它利用 Stack 层叠容器将背景层和前景层组合在一起:

@Entry
@Component
struct BlurColumnPage {
  // ... 数据定义(同上节)

  build() {
    // ══════════════════════════════════════════════════════════
    //  最外层 Stack:承载背景 + 前景毛玻璃卡片层叠
    //  Stack 允许背景和前景内容相互重叠,毛玻璃才能透过背景
    // ══════════════════════════════════════════════════════════
    Stack() {
      // ======== (1) 背景层:渐变色 + 装饰元素 ========
      this.BackgroundLayer()

      // ======== (2) 前景层:毛玻璃卡片 + Column 层叠 ========
      this.ForegroundLayer()
    }
    .width('100%')
    .height('100%')
  }

  /**
   * 背景层构建:线性渐变 + 装饰光晕
   */
  @Builder
  BackgroundLayer() {
    Column() {
      // 占位容器
      Column()
        .width('100%')
        .height('100%')
    }
    .width('100%')
    .height('100%')
    .linearGradient({
      direction: GradientDirection.Bottom,
      colors: [
        ['#0f0c29', 0],     // 顶部:深蓝黑
        ['#302b63', 0.5],   // 中部:深紫蓝
        ['#24243e', 1]      // 底部:深紫
      ]
    })

    // 粉色装饰光晕(右上角)
    Column()
      .width(280)
      .aspectRatio(1)
      .borderRadius(140)
      .backgroundColor('#ff6fd8')
      .blur(80)                // 大模糊 → 光晕感
      .position({ top: 60, right: -40 })
      .opacity(0.35)

    // 蓝色装饰光晕(左下角)
    Column()
      .width(200)
      .aspectRatio(1)
      .borderRadius(100)
      .backgroundColor('#00d4ff')
      .blur(60)
      .position({ bottom: 100, left: -30 })
      .opacity(0.25)
  }

  /**
   * 前景层构建:Scroll + Column + GlassCard 层叠列表
   */
  @Builder
  ForegroundLayer() {
    Scroll() {
      Column() {
        // 页面标题区
        this.TitleSection()

        // ★ 核心区域:毛玻璃卡片层叠 ★
        this.CardStackSection()

        // 技术说明面板
        this.TechNotesSection()
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  TitleSection() {
    Column() {
      Text('✨ 毛玻璃 · 层叠布局')
        .fontSize(26)
        .fontWeight(FontWeight.Bold)
        .fontColor('#ffffff')
        .lineHeight(34)

      Text('Column + blur + backgroundColor')
        .fontSize(13)
        .fontColor('rgba(255,255,255,0.6)')
        .margin({ top: 6 })

      Text('鸿蒙原生 ArkTS 毛玻璃效果(Frosted Glass / Glassmorphism)')
        .fontSize(12)
        .fontColor('rgba(255,255,255,0.4)')
        .margin({ top: 2 })
    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .margin({ top: 60, bottom: 20 })
  }

  @Builder
  CardStackSection() {
    Column() {
      ForEach(this.cardList, (item: GlassCardItem, idx: number) => {
        GlassCard({
          item: item,
          offsetY: idx * 16,     // ★ 每张卡片向下偏移 16vp,形成层叠 ★
          index: idx
        })
      }, (item: GlassCardItem) => item.title)

      // 底部占位空间
      Column()
        .width('100%')
        .height(40)
    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .padding({ left: 20, right: 20 })
  }

  @Builder
  TechNotesSection() {
    // 技术说明面板,也使用毛玻璃风格
    Column() {
      // ... 详细内容见完整代码
    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .padding(18)
    .backgroundColor('rgba(255, 255, 255, 0.08)')
    .blur(10)
    .border({ width: 1, color: 'rgba(255,255,255,0.15)' })
    .borderRadius(20)
    .margin({ left: 20, right: 20, top: 24, bottom: 32 })
  }
}
完整代码文件

最终完整的 BlurColumnPage.ets 文件约 375 行,由以下组件构成:

组件 行数 职责
GlassCardItem (interface) 6 卡片数据模型
GlassCard (@Component) ~90 毛玻璃卡片 UI 组件
BlurColumnPage (@Entry @Component) ~170 主页容器,组合背景+前景
GlassTipRow (@Component) ~27 说明面板中的要点行组件

所有组件在同一个 .ets 文件中定义,方便阅读和调试。在生产项目中,可以根据需要将子组件抽取到单独的文件中。

5.5 技术说明面板(GlassTipRow)

为了帮助读者理解布局原理,我们在页面底部增加了技术说明面板,其中使用了一个辅助子组件 GlassTipRow

@Component
struct GlassTipRow {
  private dotColor: string = '#ffffff';
  private text: string = '';

  build() {
    Row() {
      // 圆点指示器(带微弱发光)
      Column()
        .width(8)
        .height(8)
        .borderRadius(4)
        .backgroundColor(this.dotColor)
        .blur(2)                             // 圆点也带微弱模糊
        .margin({ right: 10 })

      // 说明文字
      Text(this.text)
        .fontSize(13)
        .fontColor('rgba(255,255,255,0.8)')
        .lineHeight(20)
        .layoutWeight(1)                      // 撑满剩余宽度
    }
    .alignItems(VerticalAlign.Top)
    .width('100%')
    .margin({ bottom: 10 })
  }
}

这个组件展示了毛玻璃风格的另一种应用——即使是小小的指示圆点,配合 blur(2) 和半透明色也能呈现出精致的光泽感。


六、布局原理深度分析

6.1 层叠偏移的计算逻辑

CardStackSection 中,每张卡片的偏移量是这样计算的:

offsetY: idx * 16     // idx 从 0 开始,所以偏移量分别为 0, 16, 32, 48

这个偏移量通过 position({ top: offsetY }) 应用到每张卡片上。由于卡片都在同一个 Column 中顺序排列,position 的 top 值使得每张卡片相对于其原本位置向下移动。偏移量递增的规律带来了视觉上的"阶梯层叠"。

为什么要使用 position 而不是 marginTop?

方式 效果 区别
marginTop 增加上方间距 卡片间的间距增大,但不会重叠
position({ top }) 相对于原位置偏移 卡片可以重叠,形成层叠效果

层叠效果的实现正是利用了 position 偏移可以让元素重叠的特性。配合毛玻璃的半透明背景,上层卡片"漏出"下层卡片的一角,层次感油然而生。

6.2 光晕装饰的实现技巧

示例中的粉色和蓝色光晕使用了一种"欺骗性"技巧——本质上是一个圆形 Column + 极高的 blur 值:

Column()
  .width(280)
  .aspectRatio(1)           // 宽高比 1:1,确保是正圆
  .borderRadius(140)        // 圆角为宽的一半 → 圆形
  .backgroundColor('#ff6fd8')
  .blur(80)                 // ★ 极高的模糊值,使圆形边缘完全虚化
  .position({ top: 60, right: -40 })
  .opacity(0.35)            // 透明度降低,使其融入背景

blur(80) 的极高模糊值使得圆形的边缘不再锐利,而是像颜料在水中晕开一样扩散开来,形成了柔和的光晕效果。这种技巧不依赖任何图片资源,纯代码实现,非常实用。

6.3 入场动画的时机控制

GlassCard 中的 .transition() 设置了插入动画:

.transition({
  type: TransitionType.Insert,
  translate: { x: 0, y: 60 },    // 从下方 60vp 处移入
  opacity: 0,                      // 从完全透明开始
  duration: 400,                   // 400ms 完成
  curve: Curve.Friction            // 摩擦曲线:开始时快,结束时慢
})

由于四张卡片都在同一个 ForEach 循环中创建,它们的动画是同时触发的。如果要实现"逐张滑入"的效果(即每张卡片依次进入),可以通过 index 参数延迟每张卡片的动画启动时间:

// 在 GlassCard 的 build() 中补充
.onAppear(() => {
  // 使用 animateTo 实现延迟动画
  animateTo({
    duration: 400,
    delay: this.index * 100,     // 每张卡片延迟 100ms
    curve: Curve.Friction
  }, () => {
    // 动画目标:无额外操作,transition 已处理
  })
})

6.4 阴影与毛玻璃效果的配合

阴影在毛玻璃效果中起着两个重要作用:

  1. 营造空间感:阴影使卡片看起来悬浮在背景之上,增强了层叠的立体感
  2. 模拟玻璃厚度:真实玻璃有厚度,会产生投影

GlassCard 中,我们使用了较大的阴影值:

.shadow({
  radius: 20,                    // 大半径 → 柔和扩散的阴影
  color: 'rgba(0, 0, 0, 0.3)',  // 半透明黑色
  offsetX: 0,                    // 无偏移 → 居中阴影
  offsetY: 8                     // 向下偏移 → 光源在正上方
})

shadow 的 radius 值越大,阴影越柔和、越扩散;offsetY 控制阴影的垂直偏移,模拟光源的方向。这里我们模拟了来自正上方的光源,所以阴影主要出现在卡片下方。


七、扩展应用场景与实践

掌握了 Column + blur + backgroundColor 的核心技术后,我们可以将其应用于多种实际场景。

7.1 场景一:音乐播放器界面

将示例中的卡片改造为音乐播放器界面:

@Component
struct MusicPlayerCard {
  build() {
    Column() {
      // 专辑封面(圆形,带光晕)
      Column()
        .width(120)
        .aspectRatio(1)
        .borderRadius(60)
        .backgroundColor('rgba(255,255,255,0.15)')
        .blur(5)
        .overlay({
          shape: Circle(),
          width: 110,
          height: 110
        })

      Blank().height(16)

      // 歌曲信息
      Text('Blur — 毛玻璃')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#ffffff')

      Text('HarmonyOS NEXT')
        .fontSize(14)
        .fontColor('rgba(255,255,255,0.6)')
        .margin({ top: 4 })

      Blank().height(24)

      // 进度条(毛玻璃风格)
      Row() {
        Column()
          .width('60%')
          .height(4)
          .backgroundColor('rgba(255,255,255,0.3)')
          .borderRadius(2)
          .overlay({
            builder: Column()
              .width('40%')
              .height('100%')
              .backgroundColor('rgba(255,255,255,0.8)')
              .borderRadius(2),
            align: Alignment.Start
          })
      }
      .width('100%')
    }
    .width('100%')
    .padding(24)
    .backgroundColor('rgba(255,255,255,0.1)')
    .blur(20)
    .borderRadius(24)
    .border({ width: 1, color: 'rgba(255,255,255,0.2)' })
  }
}

7.2 场景二:登录/注册页面

毛玻璃效果在登录页面中同样出彩:

@Component
struct GlassInputField {
  private placeholder: string = '';
  private isPassword: boolean = false;

  build() {
    Column() {
      // 输入框
      TextInput({ placeholder: this.placeholder })
        .width('100%')
        .height(48)
        .backgroundColor('rgba(255,255,255,0.08)')
        .placeholderColor('rgba(255,255,255,0.4)')
        .fontColor('#ffffff')
        .borderRadius(12)
        .padding({ left: 16 })
        .border({
          width: 1,
          color: 'rgba(255,255,255,0.15)',
          style: BorderStyle.Solid
        })
        .type(this.isPassword ? InputType.Password : InputType.Normal)
    }
    .width('100%')
    .margin({ bottom: 14 })
  }
}

7.3 场景三:数据仪表盘

多张毛玻璃卡片组合成仪表盘:

@Component
struct MetricCard {
  private label: string = '';
  private value: string = '';
  private unit: string = '';
  private trend: 'up' | 'down' | 'stable' = 'stable';

  build() {
    Column() {
      Text(this.label)
        .fontSize(12)
        .fontColor('rgba(255,255,255,0.6)')

      Blank().height(8)

      Row() {
        Text(this.value)
          .fontSize(28)
          .fontWeight(FontWeight.Bold)
          .fontColor('#ffffff')

        Text(this.unit)
          .fontSize(12)
          .fontColor('rgba(255,255,255,0.5)')
          .margin({ left: 4 })
          .alignSelf(ItemAlign.End)
          .margin({ bottom: 4 })
      }
    }
    .alignItems(HorizontalAlign.Start)
    .width('45%')
    .padding(16)
    .backgroundColor('rgba(255,255,255,0.1)')
    .blur(16)
    .borderRadius(16)
    .border({ width: 1, color: 'rgba(255,255,255,0.15)' })
  }
}

八、性能优化与最佳实践

在鸿蒙 NEXT 上使用毛玻璃效果时,以下几点优化建议可以帮助你获得更好的性能。

8.1 模糊半径的选择

blur 的半径越大,GPU 的计算负担越重。建议:

场景 推荐模糊半径 理由
主要毛玻璃面板 15~25 视觉效果明显,性能适中
装饰性元素 40~80 数量少,可以接受
列表项中的毛玻璃 10~15 列表项多,需控制性能
弹窗/对话框 20~30 临时显示,性能影响有限

8.2 半透明层叠层数控制

每叠加一层 blur + 半透明背景,GPU 就需要多一次离屏渲染(offscreen rendering)。建议:

  • 层叠深度不超过 5 层
  • 对模糊区域不重叠的卡片,使用 Scroll 容器而非多层 Stack 嵌套
  • 避免在 List / Grid 的每个 item 中都使用 blur

8.3 使用条件渲染避免不必要的模糊

在不需要毛玻璃效果的场景下,通过条件渲染避免创建模糊组件:

Column() {
  if (this.enableGlassEffect) {
    Text('毛玻璃内容')
      .backgroundColor('rgba(255,255,255,0.12)')
      .blur(20)
  } else {
    Text('普通内容')
      .backgroundColor('#ffffff')
  }
}

8.4 利用 @Builder 复用毛玻璃样式

为了避免在每个组件中重复编写毛玻璃样式代码,可以使用 @Builder 封装:

@Builder
GlassStyle(content: () => void) {
  Column() {
    content()
  }
  .width('100%')
  .padding(18)
  .backgroundColor('rgba(255, 255, 255, 0.12)')
  .blur(20)
  .borderRadius(20)
  .border({ width: 1, color: 'rgba(255,255,255,0.25)' })
}

然后在需要的地方调用:

this.GlassStyle(() => {
  Text('这是毛玻璃包裹的内容')
    .fontColor('#ffffff')
})

8.5 适配深色/浅色模式

毛玻璃效果在深色模式下效果最佳,但也可以通过条件样式适配浅色模式:

import { Configuration } from '@kit.AbilityKit';

// 在页面中监听主题变化
@State private isDarkMode: boolean = true;

aboutToAppear() {
  const config = this.getUIContext()?.getHostContext()
    ?.config as Configuration;
  this.isDarkMode = config?.colorMode === 1; // 1 = 深色
}

get glassBgColor(): string {
  return this.isDarkMode
    ? 'rgba(255, 255, 255, 0.12)'   // 深色模式:白底
    : 'rgba(0, 0, 0, 0.06)';         // 浅色模式:黑底
}

九、常见问题与调试技巧

9.1 毛玻璃效果不明显

问题:应用了 blur 和半透明背景后,看起来和普通半透明面板没什么区别。

原因分析:毛玻璃效果需要"背景有丰富的内容"才能体现。如果背景是纯色或内容很少,模糊前后的区别不大。

解决方案

  1. 确保背景层有丰富的内容(渐变色、图片、装饰元素)
  2. 增加 blur 值到 20~30
  3. 降低 backgroundColor 的 alpha 到 0.08~0.12
  4. 检查卡片是否被其他不透明组件遮挡

9.2 卡片内容也被模糊了

问题:应用 blur 后,卡片内部的文字和图标也变得模糊不清。

原因分析:blur 作用于整个组件及其子组件。如果对包含文字的卡片整体应用 blur,文字自然也会模糊。

解决方案

方法一:使用 backgroundBlurStyle(只模糊背景,不模糊内容):

Column() {
  Text('清晰的内容')
    .fontColor('#ffffff')
}
.backgroundBlurStyle(BlurStyle.Regular)
.backgroundColor('rgba(255,255,255,0.12)')

方法二:将 blur 层和内容层分离:

Stack() {
  // blur 层:只有背景,没有内容
  Column()
    .width('100%')
    .height('100%')
    .backgroundColor('rgba(255,255,255,0.12)')
    .blur(20)

  // 内容层:不模糊的文字和图标
  Column() {
    Text('清晰的内容')
      .fontColor('#ffffff')
  }
  .padding(18)
}

9.3 性能卡顿

问题:页面中包含大量毛玻璃卡片时出现卡顿。

原因分析:过多的 blur 操作消耗 GPU 资源。

解决方案

  1. 减少列表中毛玻璃卡片的数量
  2. 降低模糊半径
  3. 使用 LazyForEach 代替 ForEach 实现懒加载
  4. 对不在可视区域的卡片禁用 blur
  5. 考虑使用静态的模糊背景图片代替实时 blur

十、总结

10.1 技术回顾

本文从零到一构建了一个基于鸿蒙原生 ArkTS 的毛玻璃层叠布局示例,核心知识点包括:

技术点 API / 属性 作用
垂直布局 Column 主轴垂直排列子组件
层叠布局 Stack 允许背景和前景重叠
高斯模糊 .blur(radius) 对背景内容应用模糊
半透明色 backgroundColor rgba 控制透过程度
玻璃边框 .border rgba 模拟玻璃边缘高光
悬浮阴影 .shadow 营造立体空间感
位置偏移 .position 实现卡片层叠偏移
入场动画 .transition 卡片滑入效果

10.2 设计原则

在应用毛玻璃效果时,建议遵循以下设计原则:

  1. 层次清晰:确保背景、玻璃层、内容层三层关系明确
  2. 适度使用:毛玻璃适合点缀和强调,不宜占据整个页面
  3. 深色优先:毛玻璃在深色背景上效果最佳
  4. 性能意识:控制模糊半径和层叠数量,避免性能问题
  5. 内容可见:确保模糊后的文字依然可读,避免过度模糊

10.3 在 HarmonyOS NEXT 中的展望

随着 HarmonyOS NEXT 的持续演进,ArkUI 框架中与毛玻璃相关的 API 也在不断丰富:

  • backgroundBlurStyle:提供了系统级的标准毛玻璃样式,更加便捷
  • foregroundBlur:前景模糊,可实现更丰富的视觉效果
  • 动态模糊:结合动画实现实时变化的模糊效果

未来,毛玻璃效果在鸿蒙应用中将成为一种常见且强大的设计语言,帮助开发者构建出更富质感和层次感的用户界面。

10.4 写在最后

本文通过一个完整的示例项目,全面讲解了在 HarmonyOS NEXT 6.1.1(API 24)中使用 Column + blur + backgroundColor 实现毛玻璃层叠布局的方法。从基础原理到代码实现,从性能优化到场景扩展,希望能帮助你掌握这项实用的 UI 技术。

毛玻璃效果虽然精致,但它的实现原理并不复杂——本质上就是"半透明 + 高斯模糊"的巧妙组合。掌握了这个核心公式,你就能在鸿蒙应用中创造出无数富有创意的毛玻璃设计。

欢迎在实际项目中尝试和探索,并结合鸿蒙特有的分布式能力,打造出更具创新性的用户体验。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐