Flutter 实现 iOS 26 液态玻璃效果
本文解析 Flutter 使用 liquid_glass_widgets 实现 iOS 26 液态玻璃效果的架构与流程,涵盖 Impeller、Skia 双路径、SDF 折射与色散、液态形变、作用域配置、性能降级、选型对比及最小示例。
liquid_glass_widgets 为 Flutter 提供了一套较完整的液态玻璃实现:在 Impeller 下可通过背景纹理捕获、SDF、UV 折射、色散和高光模拟接近 iOS 26 的视觉效果,同时提供 UI 组件与液态形变动画。它并非简单的模糊滤镜,但对 Flutter 版本和渲染器有明确要求,使用前应先评估平台兼容性与 GPU 开销。
当前示例基于 liquid_glass_widgets: ^1.2.1。该版本要求 Flutter ≥ 3.41.0,并建议使用 Impeller 渲染器以获得更完整的折射效果。
一、整体架构:两层分离设计
该方案将业务组件与 GPU 渲染拆分为两个相对独立的层次。
1. liquid_glass_widgets:上层 UI 套件
上层负责向业务代码提供可直接使用的组件与状态管理能力,主要包括:
GlassCard、GlassButton、GlassAppBar、GlassModalSheet、GlassSegmentedControl等 30 多种组件;LiquidGlassScope与LiquidGlassBackground,用于管理组件树、背景范围、质量档位、自适应降级和无障碍配置;LiquidMorphEngine液态形变引擎,用于实现果冻回弹、水滴展开和弹出过渡等动画。
2. liquid_glass_renderer:底层渲染引擎
底层负责实际的 GPU 绘制工作,包括:
- 捕获玻璃组件背后的背景纹理;
- 执行 GLSL 片段着色器;
- 计算 SDF 形状、折射、色散、法线、光照与边缘高光;
- 根据 Impeller 或 Skia 自动选择渲染路径;
- 通过
BackdropGroup管理离屏纹理并隔离玻璃图层。
这种分层方式让业务开发者能够直接使用 Widget,而不必为每个组件手写 Shader。
二、核心渲染管线:Impeller 与 Skia 双路径
Flutter 应用可能运行在 Impeller 或 Skia 上。两类渲染器的底层能力和实现路径不同,因此相同代码在不同平台上可能呈现出不同效果。
路径 1:Impeller 高质量模式
使用 GlassQuality.premium 时,主要采用双 Pass 渲染流程。
Pass 1:背景模糊与纹理捕获
- 使用
BackdropFilterLayer和ImageFilter.blur对玻璃后方的内容进行高斯模糊; - 将模糊区域裁剪到玻璃组件的形状范围;
- 借助
BackdropGroup完成 GPU 离屏捕获,把背景画面保存为可供着色器采样的纹理。
Pass 2:自定义 Shader 处理
第二个 Pass 再次经过 BackdropFilterLayer,并将捕获到的背景纹理交给自定义 FragmentShader。着色器主要完成:
- 使用 SDF 计算圆角玻璃的边界;
- 偏移 UV 坐标并重新采样背景,形成折射和画面扭曲;
- 对 RGB 通道施加细微偏移,模拟色散;
- 计算表面法线、镜面高光、玻璃厚度和边缘发光;
- 混合玻璃底色、透明度与阴影。
最终像素会叠加回 Flutter UI 树。当底层内容移动时,玻璃区域中的采样画面也会同步变化,这是它与普通磨砂滤镜的主要区别。
路径 2:Skia 与 Web 轻量模式
在 Skia 或 Web 环境下,完整离屏捕获的实现成本较高,因此通常使用 GlassQuality.standard 或 GlassQuality.minimal,并通过轻量着色器完成单 Pass 绘制。
其特点包括:
- 不捕获完整的后台纹理;
- 以 Shader 模拟基础模糊、弱折射和高光;
- 折射与背景扭曲效果弱于 Impeller;
- GPU 开销较低,更适合 Web 和性能有限的设备。
因此,Impeller 与 Skia 下的显示差异通常来自渲染能力限制,并不一定是组件本身出现故障。
三、Shader 核心技术:SDF、折射、色散与光照
液态玻璃并不是在半透明容器上简单叠加模糊,而是通过多个着色器步骤模拟玻璃表面。
1. SDF 有符号距离场
SDF(Signed Distance Field)用于计算每个像素到玻璃边缘的距离。例如,圆角矩形可以抽象为以下函数:
float RBoxSDF(vec2 p, vec2 center, vec2 size, float radius)
距离值可以用于:
- 判断像素是否位于玻璃区域内;
- 推导玻璃表面的法线方向;
- 模拟玻璃厚度;
- 控制边缘区域的折射和高光强度。
与图片遮罩相比,SDF 更容易动态调整尺寸、圆角和形变参数。
2. 折射
折射的核心是根据 SDF 推导出的法线偏移 UV 坐标,再从背景纹理中采样新的像素。
可以将这一过程理解为:原本应读取 (x, y) 位置的像素,现在改为读取 (x + offsetX, y + offsetY)。当偏移量随玻璃表面变化时,底层画面就会产生类似透镜的扭曲。
普通磨砂效果通常只对背景做模糊,不改变 UV 采样位置,因此不会产生明显的折射形变。
3. 色散
色散也称 Chromatic Aberration。着色器分别偏移红、绿、蓝三个通道的采样坐标,使玻璃边缘出现轻微的彩色分离,从而增强通透感和光学质感。
4. 镜面高光与厚度模拟
着色器可以根据 SDF 梯度计算表面法线,并进一步模拟环境光和镜面反射。通常边缘被视为更厚的区域,因此折射、高光和亮边更明显;中心区域则相对平缓。
四、LiquidMorphEngine:液态形变引擎
除静态玻璃渲染外,LiquidMorphEngine 还负责组件形态之间的物理过渡。
主要能力包括:
- 物理系统与玻璃渲染逻辑相互解耦;
- 通过
GlassMorphController管理形变状态; - 支持按钮膨胀为弹窗;
- 支持模态面板以水滴形态展开;
- 支持回弹、流动和果冻式过渡;
- 可为
GlassMenu等组件提供统一的动画机制。
这使该方案不仅能绘制静态玻璃卡片,也能构建带有连续形态变化的交互界面。
五、作用域体系:LiquidGlassScope 的工作方式
如果组件只能显示普通模糊而没有折射,通常应先检查作用域配置。
1. LiquidGlassScope
LiquidGlassScope 用于创建玻璃渲染上下文,并管理背景捕获图层。一个 Scope 内应只配置一个 LiquidGlassBackground。
2. LiquidGlassBackground
LiquidGlassBackground 用来标记可被玻璃读取和折射的背景内容。只有处于正确作用域中的背景,才能被底层渲染器捕获。
3. 两种构造方式
LiquidGlassScope.stack:自动组织背景与玻璃组件的堆叠关系,适合大多数场景;- 普通构造器:需要手动配置
LiquidGlassBackground和组件层级。
常见配置问题
- 未包裹
LiquidGlassScope:无法建立折射上下文,通常只剩基础模糊; - 一个 Scope 中存在多个
LiquidGlassBackground:可能导致背景捕获或渲染异常; - 多层嵌套 Scope:内层上下文可能覆盖外层配置;
- 背景与玻璃组件不在预期层级:Shader 无法读取正确的背景纹理。
六、自适应质量与性能机制
液态玻璃会增加 GPU 负载,尤其是在页面中大量使用、组件持续移动或背景频繁更新时。该方案通过质量档位与动态降级控制开销。
1. GlassQuality 三档质量
premium:面向 Impeller 的完整双 Pass 路径,包含折射、色散和高光;standard:使用轻量着色器,在视觉效果与性能之间折中;minimal:只保留基础磨砂效果,关闭复杂折射和色散。
2. GlassAdaptiveScope
GlassAdaptiveScope 可根据设备性能和运行状态调整质量档位。例如,在设备发热或发生降频时降低渲染质量,条件恢复后再提升效果。
3. 提前预加载 Shader
建议在 main 函数中调用 LiquidGlassWidgets.initialize()。提前加载着色器可以降低首次显示玻璃组件时的闪烁和卡顿风险。
实际项目中还应注意:
- 避免在同一屏幕堆叠过多高质量玻璃组件;
- Impeller 通常比 Skia 更适合完整效果;
- Web 端优先选择
standard; - 低端设备不宜强制启用
premium。
七、与 flutter_shaders_ui 的选型对比
| 对比项 | liquid_glass_widgets 1.2.1 | flutter_shaders_ui 1.2.0 |
|---|---|---|
| 定位 | 完整的液态玻璃 UI 套件 | 通用 Shader 特效集合 |
| 折射能力 | Impeller 下支持背景捕获与 UV 折射 | 以模糊叠加为主,不强调真实背景折射 |
| UI 组件 | 提供 Card、Button、AppBar 等组件 | 主要提供独立特效 Widget |
| 物理动画 | 内置 LiquidMorphEngine | 不包含同类液态形变系统 |
| 渲染方式 | 依赖 liquid_glass_renderer,区分双路径 | 基于 Flutter FragmentShader |
| 适用场景 | 整套应用采用液态玻璃设计语言 | 背景装饰、简单磨砂和多种 Shader 特效 |
两者并非只能二选一。例如,可以使用 flutter_shaders_ui 绘制动态背景,再使用 liquid_glass_widgets 构建前景玻璃组件。
八、常见踩坑总结
- Flutter 版本不足:需要 Flutter ≥ 3.41.0,否则可能发生 Shader 编译或 API 兼容问题;
- 使用 Skia 期待完整效果:完整背景折射更依赖 Impeller,Skia 下会采用轻量路径;
- 未执行初始化:应在应用启动阶段调用
LiquidGlassWidgets.initialize(); - 缺少作用域配置:必须正确组合
LiquidGlassScope与LiquidGlassBackground; - 低端设备强制使用 premium:可能造成掉帧、发热和功耗上升;
- Web 端效果预期过高:Web 通常使用轻量渲染路径,折射强度和细节会受到限制。
九、小结
liquid_glass_widgets 的定位并非单个玻璃 Shader,而是由渲染引擎、业务组件和物理动画共同组成的解决方案。其技术重点包括跨渲染器适配、GPU 离屏纹理捕获、SDF 形状计算、背景折射以及液态形变。
如果应用需要统一采用 iOS 26 风格的液态玻璃界面,这套组件更便于快速构建;如果只是为少量区域添加模糊背景或装饰性 Shader,则可优先考虑更轻量的方案。
从实现原理看,Flutter 本身没有直接提供完整的背景折射组件。该方案通过 FragmentShader、BackdropFilterLayer 和离屏纹理捕获,在 GPU 层模拟玻璃对底层 UI 的折射与扭曲。
附录:最小示例代码
import 'package:flutter/material.dart';
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 预加载着色器,降低首次渲染时的卡顿风险。
await LiquidGlassWidgets.initialize();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: LiquidGlassScope.stack(
child: Scaffold(
body: Stack(
children: [
// 标记可被玻璃组件读取和折射的背景。
const LiquidGlassBackground(
child: FlutterLogo(size: 300),
),
Center(
child: GlassCard(
quality: GlassQuality.premium,
child: const Padding(
padding: EdgeInsets.all(24),
child: Text('Liquid Glass Demo'),
),
),
),
],
),
),
),
);
}
}





暂无评论,期待您的发言...