最近在做一个 AI 耳机 App 的 Welcome 启动页 UI 改造。

这个页面原本已经有一版夜间模式,而且夜间模式的布局、按钮、耳机位置和交互都已经基本定稿。因此这次改造的目标不是重新设计一个页面,而是在不破坏夜间模式的前提下,为白天模式补上一套更干净、更高级的浅蓝灰智能硬件风格。

最终目标风格大致是:

浅蓝灰背景
低饱和蓝色点缀
白色半透明质感
柔和阴影
透明白色耳机主视觉
简约高级的智能硬件产品感

一、问题背景

最开始白天模式效果并不理想,主要问题集中在几个地方:

  1. 耳机像是用 Flutter Widget 或 CustomPaint 临时画出来的,质感不够。

  2. 耳机区域出现明显的灰色或白色矩形底板。

  3. 背景波纹和耳机没有融合,看起来像直接贴了一张图。

  4. logo 资源异常,显示出了多余画布或非目标内容。

  5. 页面整体只是“夜间模式换浅色皮肤”,没有智能硬件欢迎页的空气感。

一开始我以为是布局没调好,后来排查发现,核心问题并不是布局,而是资源和实现路线不对

夜间模式可以用代码绘制出比较酷的深色霓虹效果,但白天模式想要做出透明、轻拟物、玻璃感的耳机,如果继续用 Flutter Widget 强行画,很难接近目标效果。

二、核心原则

这次改造定了几个原则:

  1. 夜间模式保持不变。

  2. 不改路由、不改登录跳转、不改按钮点击逻辑。

  3. 白天模式耳机不再用 Flutter 手动画。

  4. 白天模式耳机必须使用真正透明背景的 PNG。

  5. 背景和 logo 可以用 Flutter 代码绘制,避免依赖异常图片资源。

  6. 不用 Container、ClipRRect、Opacity、ColorFilter 去“伪装”素材问题。

也就是说,耳机必须是干净的图片资源,背景和 logo 则可以通过轻量 CustomPaint 实现。

三、素材检查

白天模式耳机素材统一放在:

assets/images/transparent_earphones.png

重新检查后的图片信息如下:

size: 1254 x 1254
mode: RGBA
has_alpha: true
transparent pixels: about 71.8%
corners alpha: 0, 0, 0, 0

这说明图片确实有 alpha 透明通道,四个角也是透明的,不会天然显示白色或灰色矩形底板。

pubspec.yaml 中使用目录方式引入资源:

flutter:
  uses-material-design: true
  assets:
    - assets/images/

只要图片放在 assets/images/ 目录下,Flutter 就可以正常加载。

这里有一个细节需要注意:
文件名最好不要带空格,比如不要写成:

transparent_earphones .png

建议统一成:

transparent_earphones.png

避免 Flutter asset 路径出现不必要的问题。

四、一次失败尝试:用 HTML 还原视觉稿

中间也尝试过一种方式:先根据目标 UI 图片生成一份高保真的 HTML + CSS 静态页面,再参考 HTML 的结构和样式去改 Flutter。

这个方法在视觉分析阶段有一定帮助,比如可以快速拆出页面结构、颜色、字号、按钮圆角、背景装饰等。

但是实际接入 Flutter 时效果并不理想。

主要原因是 HTML 页面更多是“静态视觉还原”,而 Flutter 项目里已经有现成的夜间模式布局、主题切换、按钮交互和页面结构。如果直接按 HTML 方式迁移,很容易出现几个问题:

  1. Flutter 页面比例和 HTML 设计稿不一致。

  2. 耳机素材仍然受到图片透明度影响。

  3. 背景波纹、按钮、耳机位置很难直接对应。

  4. 容易破坏原本已经定好的夜间模式布局。

  5. 最后效果更像“重新写了一个页面”,而不是在原页面上适配白天模式。

所以这个方案没有作为最终主方案,只保留了它的参考价值:
HTML 可以用来确认视觉方向,但不适合作为最终 Flutter 实现依据。

最终还是回到 Flutter 原生实现路线:夜间模式保持原样,白天模式单独做主题隔离;耳机使用真正透明 PNG;背景和 logo 用轻量绘制控制。

五、白天模式实现思路

1. 背景

白天模式背景不再强依赖 bg_wave.png 图片,而是通过 Flutter 绘制:

  • 顶部浅蓝灰到白色渐变;

  • 很淡的弧形波纹;

  • 右上角点阵;

  • 少量浅蓝小光点;

  • 耳机后方淡蓝波纹;

  • 底部轻微曲线装饰。

这样可以避免背景图本身带白底、灰底或被拉伸变形的问题。

白天模式的背景重点不是“蓝”,而是“淡”。
蓝色只作为局部点缀,不能铺满整个页面。

2. Logo

之前的 logo_icon.png 不是一个干净的 logo 图,而是一张展示图,里面有多个 logo、棋盘格、白底和文件名。

所以白天模式顶部 logo 不再直接使用这张异常图片,而是用 CustomPaint 画一个简洁的小图标:

  • 蓝色圆点;

  • 三段声波弧线;

  • 小巧居中;

  • 没有白底;

  • 没有多余文字;

  • 不会显示图片文件名或异常画布。

3. 耳机主视觉

白天模式耳机只使用透明 PNG:

Image.asset(
  'assets/images/transparent_earphones.png',
)

这里有一个重点:
耳机图片外层不加背景色、不加 Card、不加白色底板、不加灰色底板。

如果图片本身是真透明,那么它就可以自然悬浮在浅蓝灰背景和波纹之上。

如果图片本身不透明,再怎么用 Flutter 包 Container、ClipRRect、Opacity,都只是掩盖问题,最后一定会出现矩形底板或者发灰的问题。

六、页面结构

白天模式 Welcome 页仍保持原来的结构:

顶部小 logo
OUCCL
Welcome
短横线
Smart listening.
Beautifully connected.
耳机主视觉
Get Started
Sign in

没有新增功能模块,也没有修改交互逻辑。

Get Started 仍然负责进入主流程,Sign in 仍然作为次级登录入口。

七、关键代码方向

耳机区域的实现思路大致如下:

Stack(
  alignment: Alignment.center,
  children: [
    Positioned.fill(
      child: CustomPaint(
        painter: _LightHeroWavePainter(...),
      ),
    ),
    Image.asset(
      'assets/images/transparent_earphones.png',
      width: earphoneImageWidth,
      height: earphoneImageHeight,
      fit: BoxFit.fill,
    ),
  ],
)

这里没有强制保持图片原始等比例。

原因是这个耳机图本身有较大的透明留白,如果完全使用 BoxFit.contain,在页面里的视觉大小可能会偏小。实际处理时,可以在白天模式下单独设置耳机图片的显示宽高,让它在视觉上接近目标效果即可。

但需要注意:

可以轻微非等比缩放;
不要拉伸到明显变形;
不要裁切;
不要加背景容器;
不要出现矩形底板;
只在 light mode 下生效。

夜间模式仍然保留原来的耳机绘制方式,不受白天模式影响。

八、按钮和文字处理

白天模式的文字颜色主要分三层:

主标题:深蓝黑
副标题:灰蓝色
按钮文字:白色

例如:

  • OUCCL 使用深蓝黑,字距略大;

  • Welcome 使用深蓝黑,字重较高;

  • Smart listening. Beautifully connected. 使用灰蓝色;

  • 短横线使用浅蓝渐变;

  • Get Started 使用柔和亮蓝胶囊按钮;

  • Sign in 使用蓝色文字和小箭头。

按钮不能过于科技蓝,也不能发光太重。
整体还是要保持浅蓝灰、干净、轻盈的智能硬件风格。

九、light / dark 隔离

这次改造中最重要的一点是:
白天模式和夜间模式必须隔离。

夜间模式已经定稿,所以不能因为白天模式改造影响原来的夜间效果。

实现上可以通过 isLight 判断:

if (isLight) {
  // 白天模式:使用透明 PNG 耳机 + 浅蓝灰背景
} else {
  // 夜间模式:继续使用原来的深色霓虹效果
}

需要特别避免:

  1. 把白天模式耳机影响到夜间模式。

  2. 把白天模式背景渐变影响到夜间模式。

  3. 改动 Get StartedSign in 的跳转逻辑。

  4. 为了还原白天模式而重构整个页面。

本次改造应该是“在原页面上适配白天主题”,而不是重新写一个 Welcome 页。

十、最终效果目标

最终白天模式的目标是:

  • 浅蓝灰白色渐变背景;

  • 干净、轻盈、柔和;

  • 透明白色耳机自然悬浮;

  • 淡蓝波纹和点阵作为装饰;

  • 深蓝黑文字;

  • 灰蓝色标语;

  • 柔和蓝色胶囊按钮;

  • Sign in 作为蓝色次级入口。

整体方向是智能硬件产品欢迎页,而不是普通白底页面,也不是夜间模式的浅色换皮。

十一、经验总结

这次最大的教训是:
UI 效果差,不一定是代码布局的问题。

如果素材本身不合格,后面再怎么调布局和颜色,效果都很难好。

尤其是透明耳机这种主视觉,如果素材不是透明 PNG,就很容易出现:

白色矩形底板
灰色背景块
图片像直接贴上去
背景和主体不融合

正确做法应该是:

  1. 先检查素材是否合格。

  2. 图片该透明就必须真的透明。

  3. 背景装饰尽量独立绘制,或者使用真正透明纹理。

  4. 不要用代码强行修坏素材。

  5. 夜间模式已定稿时,白天模式要严格隔离实现。

  6. HTML 可以辅助分析视觉,但不应直接决定 Flutter 的最终实现方式。

这次改造后,白天模式 Welcome 页的实现路线更清晰:

耳机用透明 PNG;
背景和 logo 用轻量绘制;
颜色通过主题隔离;
布局和交互保持原有逻辑;
夜间模式不受影响。

这样既能接近目标视觉效果,也能减少对原有代码和夜间模式的破坏。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐