44岁被裁后用AI写鸿蒙App(4):UIDesignKit UI——光感玻璃 + 流光交互实战

0 阅读6分钟

44岁被裁后用AI写鸿蒙App(4):UIDesignKit UI——光感玻璃 + 流光交互实战

上一篇 44岁被裁后用AI写鸿蒙App(3):AGC 认证 + 云函数 + 端到端加密实战一个人搞定全栈后端:AGC 手机号登录 - 掘金

给 App 加一点"光",视觉质感从工具级升到产品级。 而且代码量比你想象得少得多。

前言:为什么要在 UI 上下这个功夫

my-parents-helper 是一个给老人用的 App。你可能会觉得:老人又不看颜值,UI 做得好看有什么用?

我的答案是:好用和好看不冲突。

鸿蒙老的视觉风格比较沉闷——按钮扁平、颜色单一、缺少层次感。这不只是好不好看的问题,它还影响使用体验:

  • 按钮跟背景没有区分度 → 老人看不清"哪里可以点"
  • 页面缺乏层次感 → 看不清"我现在在哪个页面"
  • 界面没有反馈感 → 点了不知道点没点中

鸿蒙 @kit.UIDesignKit 提供的视觉特效能力,可以很好地解决这些问题。而且——它真的不难写。


一、核心概念:ShaderEffect + HdsEffectBuilder

鸿蒙 UIDesignKit 的核心是一个叫 HdsEffectBuilder 的工厂类,你通过链式调用配置各种特效,最后调用 .buildEffect() 生成一个 VisualEffect 对象,挂到任何 UI 组件的 .visualEffect() 上。

import { hdsEffect } from '@kit.UIDesignKit';

Button('发送')
  .visualEffect(
    new hdsEffect.HdsEffectBuilder()
      .shaderEffect({ ... })  // 着色器效果
      .pointLight({ ... })     // 点光源效果
      .buildEffect()           // 生成 VisualEffect
  )

整个过程就是搭积木。你要哪种效果,就在 builder 上加什么。


登录.jpg

父母端我的.jpg

模型配置.jpg

二、流光效果:让按钮"活"起来

DUAL_EDGE_FLOW_LIGHT

这是 UIDesignKit 最实用的效果——双边流光。按钮的两条边缘会有颜色流动,像光在表面滑动。

我的 GlowEffect 封装(约 100 行)就是这个效果的一个通用工厂:

// commons/uicomponents → effects/GlowEffect.ets
import { hdsEffect } from '@kit.UIDesignKit';

export class GlowEffect {
  static glowFlow(
    controller: hdsEffect.ShaderEffectController,
    isActive: boolean,
    params?: { firstColor, secondColor, duration }
  ): Object {
    const builder = new hdsEffect.HdsEffectBuilder()
      .shaderEffect({
        effectType: hdsEffect.EffectType.DUAL_EDGE_FLOW_LIGHT,
        animation: {
          duration: isActive ? 800 : 3000,  // 活跃时快闪,常驻时慢呼吸
          iterations: -1,                     // 无限循环
          autoPlay: true,
        },
        controller: controller,
        params: {
          firstEdgeFlowLight: { startPos: 0, endPos: 1.0, color: '#FF8C5A' },
          secondEdgeFlowLight: { startPos: 0.5, endPos: 1.5, color: '#FFE0D0' },
        },
      });
    
    // 可以附加点光源,让边缘更有立体感
    builder.pointLight({
      illuminatedType: hdsEffect.PointLightIlluminatedType.BORDER,
    });
    
    return builder.buildEffect();
  }
}

使用方式极简。每个需要流光的控件建一个独立的 controller:

@ComponentV2
export struct LoginPage {
  @Local loginBtnCtrl: hdsEffect.ShaderEffectController = new hdsEffect.ShaderEffectController();
  @Local codeBtnCtrl: hdsEffect.ShaderEffectController = new hdsEffect.ShaderEffectController();

  build() {
    Column() {
      // 获取验证码按钮 — 常驻流光
      Button('获取验证码')
        .visualEffect(GlowEffect.ambientGlow(this.codeBtnCtrl))
      
      // 登录按钮 — 可条件切换脉冲/常驻
      Button('登录')
        .visualEffect(GlowEffect.glowFlow(this.loginBtnCtrl, this.isLoading))
    }
  }
}

常驻流光 vs 脉冲流光

模式适用场景动画时长视觉效果
ambientGlow按钮常规态、背景装饰3000ms慢速呼吸流动,不抢眼
pulseGlow点击反馈、提醒、通知800ms快速亮色一闪,吸引注意
glowFlow(isActive)条件切换根据状态active 时快闪,平时常驻

使用场景示例:

组件效果原因
⚙️ 设置按钮ambientGlow右上角齿轮按钮,常驻流光提升质感
📋 复制日志按钮ambientGlow调试面板里的操作按钮
🔵 登录按钮glowFlow(isActive)点击时触发脉冲,反馈用户"正在处理"
🔐 生物识别按钮glowFlow(isActive)认证过程中闪烁提示

为什么不直接用组件封装,而是工厂函数

你可能会想:为什么不用一个 @ComponentV2 struct GlowButton 来封装?

因为 .visualEffect() 是直接挂在不同类型的基础组件上(ButtonRowText),用组件封装会多一层 DOM 嵌套,影响布局。工厂函数直接返回 VisualEffect 对象,挂上去就行,不影响现有的 UI 结构。


三、点光源效果:给组件加"立体感"

流光是在边缘流动的,但要让组件看起来有"微凸起"的立体感,还需要点光源。

// 单独使用点光源
new hdsEffect.HdsEffectBuilder()
  .pointLight({
    illuminatedType: hdsEffect.PointLightIlluminatedType.BORDER,
  })
  .buildEffect()

PointLightIlluminatedType.BORDER 会在组件边缘生成一个微弱的亮光,模拟光线从侧面照射的效果。

流光和点光源通常是组合使用的——光在边缘流动 + 边缘被照亮 = 组件像玻璃一样通透。


四、玻璃拟态:通透的卡片背景

除了流光,我还用到了鸿蒙的背景模糊能力来实现"玻璃"效果。

鸿蒙的 BlurStyle 组件可以直接给任何容器加毛玻璃效果:

Column() {
  // 卡片内容
}
.backgroundBlurStyle(BlurStyle.Thin)
.backgroundColor('#80FFFFFF')  // 半透明白
.borderRadius(16)

配合渐变背景,可以做出很通透的层级感:

// 主页面渐变背景
Column()
  .width('100%')
  .height('100%')
  .linearGradient({
    angle: '180deg',
    colors: [['#F0ECFF', 0], ['#EEFFF5', 1]]
  })

顶层放毛玻璃卡片,底层是渐变背景——两层叠加,效果不输那些大厂的 App。


五、实际效果:登录页面的完整流光按钮

这是 LoginPage 里一个典型的流光按钮——获取验证码按钮:

Button(this.emailCodeCountdown > 0 ?
  `${this.emailCodeCountdown}s` :                   // 倒计时
  (this.emailCodeSending ? '发送中' : '获取验证码'))   // 状态文字
  .fontSize(14)
  .fontColor(Color.White)
  .padding({ left: 10, right: 10 })
  .height(48)
  .borderRadius(8)
  .backgroundColor('#E0E0E0')   // 按钮底色
  .visualEffect(new hdsEffect.HdsEffectBuilder()
    .shaderEffect({
      effectType: hdsEffect.EffectType.DUAL_EDGE_FLOW_LIGHT,
      animation: { duration: 3000, iterations: -1, autoPlay: true },
      controller: this.codeBtnCtrl,
      params: {
        firstEdgeFlowLight: { startPos: 0, endPos: 1.0, color: '#FF8C5A' },
        secondEdgeFlowLight: { startPos: 0.5, endPos: 1.5, color: '#FFE0D0' },
      },
    })
    .pointLight({ illuminatedType: hdsEffect.PointLightIlluminatedType.BORDER })
    .buildEffect()
  )
  .enabled(this.emailCodeCountdown === 0)
  .onClick(() => this.onEmailCodeSend())

这段代码的效果:按钮四边有暖橙色光晕缓缓流动,倒计时 60 秒内按钮禁用,流光暂停——60 秒后流光恢复,提示用户可以再次点击。


六、设计原则:不要过度设计

最后说一个重要的原则:UI 特效是"调味料"不是"主菜"。

这个 App 的用户是老人。我遵循几条规则:

规则原因
只在操作按钮上用流光告诉老人"这里可以点"
只在设置页用毛玻璃区分内容层级,不干扰阅读
减速动画老人反应速度慢,动画太快会晕
大按钮 + 高对比度视觉特效是点缀,大字大按钮才是核心
不引入外部动效库鸿蒙系统能力完全够用,不增加包体积

小结

鸿蒙 @kit.UIDesignKit 的能力总结:

效果核心 API使用位置
流光(边缘流动)EffectType.DUAL_EDGE_FLOW_LIGHT按钮、图标
点光源(边缘照亮)PointLightIlluminatedType.BORDER按钮、卡片
玻璃拟态(毛玻璃)backgroundBlurStyle(BlurStyle)设置页卡片
渐变背景.linearGradient()主页面背景
组合特效HdsEffectBuilder 链式调用任意组件

全部代码在 GlowEffect.ets(约 100 行),每个控件只需 3 行就能挂上流光效果。投入产出比极高。


下篇预告

第5篇:踩坑合集——@ObservedV2 + Repeat、编译报错、组件化重构

我会把开发过程中遇到的最有价值的坑整理出来——那些你查文档也查不到的"鸿蒙专属"问题。

关注我 seal_jing,一个正在鸿蒙生态里写 App 的独立开发者。


发布时间:2026年6月 作者:seal_jing,44岁、被裁、血压已恢复正常、正在写代码