Flutter 应该如何实现 iOS 26 的 Liquid Glass
要在 Flutter 中实现 iOS 26 的Liquid Glass(液态玻璃) 视觉交互效果,需先明确 Liquid Glass 的核心特征:iOS 26 推出的液态玻璃质感聚焦「动态流体形变、玻璃拟态(Glassmorphism)进阶版、触控反馈的液态柔化、层级通透的光影融合」,结合 Flutter 的渲染特性,可通过自定义绘制 + 物理动效 + 材质渲染 三层核心逻辑实现,以下是分步实现方案:
一、核心原理与技术选型
Liquid Glass 的核心视觉要素:
- 「通透感」:半透明模糊 + 背景融合(类似 iOS 磨砂玻璃,但动态适配内容);
- 「液态形变」:触控 / 滚动时的流体拉伸、回弹物理效果;
- 「光影层级」:动态渐变 + 高斯模糊 + 阴影随交互实时变化;
- 「柔化反馈」:触控时的液态按压、回弹动效。
Flutter 侧核心技术:
- 模糊 / 通透:
BackdropFilter+ImageFilter.blur实现磨砂玻璃; - 动态形变:
CustomPainter自定义绘制贝塞尔曲线模拟流体; - 物理动效:
physics: BouncingScrollPhysics()(iOS 原生回弹)+AnimationController控制形变动画; - 光影融合:
Gradient渐变 +BoxShadow动态调整阴影参数。
二、分步实现核心效果
1. 基础:Liquid Glass 的通透玻璃底版
先实现 Liquid Glass 的基础质感 —— 比传统 Glassmorphism 更通透、更贴合 iOS 26 的液态模糊:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
// 液态玻璃容器组件
class LiquidGlassContainer extends StatelessWidget {
final Widget child;
final double blur; // 模糊度(iOS 26建议8-12)
final Color tintColor; // 液态染色(浅白/浅蓝,贴近iOS系统)
final double borderRadius;
const LiquidGlassContainer({
super.key,
required this.child,
this.blur = 10.0,
this.tintColor = const Color(0x80FFFFFF), // 80%不透明的白,模拟液态通透
this.borderRadius = 20.0,
});
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
child: Container(
decoration: BoxDecoration(
color: tintColor,
// 液态光影:多层浅阴影模拟玻璃厚度+液态反光
boxShadow: [
BoxShadow(
color: Colors.white.withOpacity(0.4),
blurRadius: 8,
offset: const Offset(-2, -2), // 上左高光
),
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(2, 2), // 下右阴影
),
],
// 液态边框:极细的通透边框,模拟玻璃边缘
border: Border.all(
color: Colors.white.withOpacity(0.2),
width: 0.8,
),
),
child: child,
),
),
);
}
}
使用示例(嵌入页面):
dart
Scaffold(
body: Stack(
children: [
// 背景图(模拟页面内容,让模糊有依托)
Image.asset(
'assets/background.jpg',
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
// 液态玻璃卡片
Positioned(
top: 100,
left: 20,
right: 20,
child: LiquidGlassContainer(
child: Padding(
padding: const EdgeInsets.all(20),
child: Text(
'iOS 26 Liquid Glass',
style: TextStyle(fontSize: 24, color: Colors.black87),
),
),
),
),
],
),
);
2. 核心:触控触发的液态形变效果
Liquid Glass 的核心是「触控时的流体形变」,通过
CustomPainter绘制动态贝塞尔曲线,结合GestureDetector监听触控位置,实现液态拉伸 / 回弹:dart
class LiquidGlassInteractive extends StatefulWidget {
final Widget child;
const LiquidGlassInteractive({super.key, required this.child});
@override
State<LiquidGlassInteractive> createState() => _LiquidGlassInteractiveState();
}
class _LiquidGlassInteractiveState extends State<LiquidGlassInteractive>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
Offset _touchPosition = Offset.zero; // 触控位置
bool _isPressed = false; // 是否按压
@override
void initState() {
super.initState();
// 回弹动画控制器(模拟液态回弹的物理效果)
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
curve: Curves.elasticOut, // 弹性曲线,贴近液态回弹
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (details) {
setState(() {
_touchPosition = details.localPosition;
_isPressed = true;
});
_controller.forward(from: 0); // 触发回弹动画
},
onTapUp: (details) {
setState(() => _isPressed = false);
},
onTapCancel: () {
setState(() => _isPressed = false);
},
child: CustomPaint(
painter: LiquidGlassPainter(
touchPosition: _touchPosition,
isPressed: _isPressed,
animationValue: _controller.value,
),
child: LiquidGlassContainer(child: widget.child),
),
);
}
}
// 自定义液态形变绘制器
class LiquidGlassPainter extends CustomPainter {
final Offset touchPosition;
final bool isPressed;
final double animationValue;
LiquidGlassPainter({
required this.touchPosition,
required this.isPressed,
required this.animationValue,
});
@override
void paint(Canvas canvas, Size size) {
if (!isPressed) return;
// 液态形变半径(随动画回弹)
final double radius = 80 * (1 - animationValue);
// 液态笔触:柔化的圆形渐变,模拟按压时的液体扩散
final Paint paint = Paint()
..shader = RadialGradient(
center: Alignment.center,
radius: 1.0,
colors: [
Colors.white.withOpacity(0.3),
Colors.transparent,
],
).createShader(Rect.fromCircle(center: touchPosition, radius: radius))
..blendMode = BlendMode.overlay; // 叠加模式,贴合底层玻璃质感
// 绘制液态按压形变
canvas.drawCircle(
touchPosition,
radius,
paint,
);
// 绘制流体拉伸的贝塞尔曲线(模拟液体向四周延伸)
final Path path = Path()
..moveTo(touchPosition.dx - radius, touchPosition.dy)
..quadraticBezierTo(
touchPosition.dx,
touchPosition.dy - radius * 0.8,
touchPosition.dx + radius,
touchPosition.dy,
)
..quadraticBezierTo(
touchPosition.dx,
touchPosition.dy + radius * 0.8,
touchPosition.dx - radius,
touchPosition.dy,
);
canvas.drawPath(path, paint..opacity = 0.15);
}
@override
bool shouldRepaint(covariant LiquidGlassPainter oldDelegate) {
return oldDelegate.touchPosition != touchPosition ||
oldDelegate.isPressed != isPressed ||
oldDelegate.animationValue != animationValue;
}
}
使用示例(带交互的液态玻璃按钮 / 卡片):
dart
LiquidGlassInteractive(
child: SizedBox(
width: 300,
height: 100,
child: Center(
child: Text(
'液态玻璃交互按钮',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
),
),
)
3. 进阶:滚动时的液态柔化适配
iOS 26 Liquid Glass 在滚动时会随内容偏移动态调整模糊 / 形变,需结合
ScrollController监听滚动偏移,实时更新玻璃效果参数:dart
class LiquidGlassScrollable extends StatefulWidget {
const LiquidGlassScrollable({super.key});
@override
State<LiquidGlassScrollable> createState() => _LiquidGlassScrollableState();
}
class _LiquidGlassScrollableState extends State<LiquidGlassScrollable> {
final ScrollController _scrollController = ScrollController();
double _scrollOffset = 0.0;
@override
void initState() {
super.initState();
// 监听滚动偏移,动态调整液态玻璃参数
_scrollController.addListener(() {
setState(() {
_scrollOffset = _scrollController.offset;
});
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// 滚动时模糊度随偏移动态变化(模拟液态流动)
final double dynamicBlur = 10 + (_scrollOffset / 100) % 5;
// 滚动时染色透明度随偏移变化(模拟液态深浅)
final double dynamicOpacity = 0.8 - (_scrollOffset / 1000).clamp(0, 0.3);
return Scaffold(
body: Stack(
children: [
// 滚动列表(底层内容)
ListView.builder(
controller: _scrollController,
itemCount: 50,
itemBuilder: (context, index) => ListTile(
title: Text('列表项 $index'),
),
),
// 顶部悬浮液态玻璃栏(随滚动动态变化)
Positioned(
top: 0,
left: 0,
right: 0,
child: LiquidGlassContainer(
blur: dynamicBlur,
tintColor: Color(0x${(dynamicOpacity * 255).toInt().toRadixString(16).padLeft(2, '0')}FFFFFF),
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 16),
child: Text(
'动态液态玻璃标题栏',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
),
),
],
),
);
}
}
三、关键优化(贴合 iOS 26 原生体验)
-
性能优化:
BackdropFilter是重量级组件,需限制使用范围(避免全屏模糊),可通过RepaintBoundary隔离渲染层,减少重绘;- 动态形变的
CustomPainter需控制shouldRepaint逻辑,仅在参数变化时重绘,避免过度渲染。
-
系统适配:
- 结合
TargetPlatform.iOS判断平台,仅在 iOS 端启用 Liquid Glass 效果,安卓端降级为普通磨砂玻璃; - 适配 iOS 26 的系统配色:使用
CupertinoColors中的系统色(如CupertinoColors.systemBackground),让液态玻璃贴合系统主题。
- 结合
-
物理动效调优:
- 动画曲线优先使用
Curves.elasticOut/Curves.bounceOut模拟液态回弹; - 触控形变的半径、透明度需贴合 iOS 原生参数(建议半径 80-100,透明度 0.2-0.4)。
- 动画曲线优先使用
四、补充:依赖与兼容性
- Flutter 版本:建议使用 Flutter 3.16+(对
BackdropFilter和CustomPainter的渲染优化更好); - iOS 适配:需在
Info.plist中开启UIBlurEffect相关权限(无需额外配置,Flutter 已封装); - 进阶扩展:可结合
flutter_physics库增强物理动效,或glassmorphism库简化基础玻璃效果(但需自定义扩展液态形变)。
通过以上方案,可实现接近 iOS 26 原生 Liquid Glass 的视觉和交互效果 —— 核心是「通透模糊 + 动态流体形变 + 物理动效」的结合,既还原系统级的液态质感,又适配 Flutter 的跨平台渲染特性。

浙公网安备 33010602011771号