一、什么是高斯模糊?
高斯模糊,英文叫 Gaussian Blur,是一种常见的图像模糊算法。
它的作用是让图片、背景、组件边缘变得柔和,常用于:
- 毛玻璃效果
- 图片背景虚化
- 弹窗背景模糊
- 卡片半透明背景
- 登录页背景处理
- 音乐播放页封面背景
- 图片加载占位
- 隐私信息遮挡
在 Flutter 中,高斯模糊最常见的实现方式主要有两个:
- BackdropFilter
- ImageFiltered
它们都可以配合 dart:ui 中的 ImageFilter.blur() 实现模糊效果。
二、核心 API:ImageFilter.blur
Flutter 中的模糊能力来自 dart:ui:
dart
import 'dart:ui';
常用写法:
dart
ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
)
参数说明:
- sigmaX:水平方向模糊强度
- sigmaY:垂直方向模糊强度
一般参考取值:
- sigma 3 - 5:轻微模糊
- sigma 8 - 15:常规毛玻璃
- sigma 20+:强模糊,性能压力更大
注意:sigma 并不是越大越好。模糊半径越大,GPU 计算成本越高,页面越容易掉帧。
三、BackdropFilter 和 ImageFiltered 的区别
这是 Flutter 高斯模糊里最容易混淆的地方。
1. BackdropFilter:模糊「背后的内容」
BackdropFilter 会对当前组件背后已经绘制好的内容进行模糊。
适合做:
- 毛玻璃卡片
- 弹窗背景模糊
- 底部导航栏毛玻璃
- AppBar 毛玻璃
- 局部区域背景虚化
官方定义中,BackdropFilter 是对已经绘制的内容应用过滤器,然后再绘制自己的 child。并且多个 BackdropFilter 在共享 BackdropKey 时,可以由 Flutter 引擎合并为一次渲染操作,从而降低开销。
2. ImageFiltered:模糊「自己的 child」
ImageFiltered 会直接对它包裹的子组件进行模糊。
适合做:
- 模糊一张图片
- 模糊一个 Widget
- 模糊头像、封面、背景图
- 做隐私遮挡效果
简单总结:
- BackdropFilter:模糊我背后的东西
- ImageFiltered:模糊我包住的东西
四、实现一:使用 ImageFiltered 模糊图片
如果你只是想模糊一张图片,优先使用 ImageFiltered。
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurImagePage extends StatelessWidget {
const BlurImagePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Image.asset(
'assets/images/bg.jpg',
width: 300,
height: 200,
fit: BoxFit.cover,
),
),
),
);
}
}
效果特点:
- 原图本身被模糊
- 不会影响图片背后的其他组件
适合场景:
- 背景图虚化
- 封面图虚化
- 头像隐私处理
- 图片占位背景
五、实现二:使用 BackdropFilter 实现毛玻璃效果
毛玻璃效果的本质是:背景模糊 + 半透明蒙层 + 圆角裁剪
示例代码:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class FrostedGlassPage extends StatelessWidget {
const FrostedGlassPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: [
Image.asset(
'assets/images/bg.jpg',
fit: BoxFit.cover,
),
Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 16,
sigmaY: 16,
),
child: Container(
width: 300,
height: 180,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(24),
border: Border.all(
color: Colors.white.withOpacity(0.3),
),
),
child: const Text(
'Flutter 毛玻璃效果',
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
],
),
);
}
}
关键点:
- Stack 先绘制背景图
- BackdropFilter 对背景图进行模糊
- ClipRRect 限制模糊范围
- Container 添加半透明背景
- Border 增强玻璃质感
如果没有 ClipRRect 或 ClipRect,BackdropFilter 可能会影响更大的区域,甚至整个屏幕。Flutter API 文档也说明,如果需要让过滤器只作用于子组件区域,应结合 clip 使用。
六、封装一个通用毛玻璃组件
实际项目中,不建议每个地方都重复写 ClipRRect + BackdropFilter + Container,可封装通用组件:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class GlassContainer extends StatelessWidget {
const GlassContainer({
super.key,
required this.child,
this.width,
this.height,
this.borderRadius = 20,
this.blur = 16,
this.padding = const EdgeInsets.all(16),
this.backgroundColor,
this.borderColor,
});
final Widget child;
final double? width;
final double? height;
final double borderRadius;
final double blur;
final EdgeInsetsGeometry padding;
final Color? backgroundColor;
final Color? borderColor;
@override
Widget build(BuildContext context) {
final radius = BorderRadius.circular(borderRadius);
return ClipRRect(
borderRadius: radius,
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: blur,
sigmaY: blur,
),
child: Container(
width: width,
height: height,
padding: padding,
decoration: BoxDecoration(
color: backgroundColor ?? Colors.white.withOpacity(0.18),
borderRadius: radius,
border: Border.all(
color: borderColor ?? Colors.white.withOpacity(0.28),
),
),
child: child,
),
),
);
}
}
使用方式:
dart
GlassContainer(
width: 320,
height: 180,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
Icons.flutter_dash,
color: Colors.white,
size: 48,
),
SizedBox(height: 12),
Text(
'Flutter 高斯模糊',
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
],
),
)
七、实现三:模糊弹窗背景
很多 App 弹窗出现时,页面背景变暗并模糊,实现代码:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
Future<void> showBlurDialog(BuildContext context) {
return showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: 'blur_dialog',
barrierColor: Colors.black.withOpacity(0.2),
pageBuilder: (context, animation, secondaryAnimation) {
return BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 8,
sigmaY: 8,
),
child: Center(
child: Material(
color: Colors.transparent,
child: Container(
width: 280,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: const Text(
'这是一个带背景模糊的弹窗',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
),
),
),
);
},
);
}
调用方式:
dart
ElevatedButton(
onPressed: () {
showBlurDialog(context);
},
child: const Text('显示模糊弹窗'),
)
适用场景:
- 登录提示弹窗
- 权限说明弹窗
- 会员弹窗
- 图片预览弹窗
- 操作确认弹窗
八、实现四:毛玻璃 AppBar
顶部导航栏实现毛玻璃模糊效果:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurAppBarPage extends StatelessWidget {
const BlurAppBarPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 12,
sigmaY: 12,
),
child: AppBar(
backgroundColor: Colors.white.withOpacity(0.15),
elevation: 0,
title: const Text('毛玻璃 AppBar'),
),
),
),
),
body: ListView.builder(
padding: EdgeInsets.zero,
itemCount: 30,
itemBuilder: (context, index) {
return SizedBox(
height: 100,
child: Center(
child: Text('Item $index'),
),
);
},
),
);
}
}
关键点:
- Scaffold 设置
extendBodyBehindAppBar: true - AppBar 外层包裹 BackdropFilter
- 使用 ClipRect 限制模糊区域
- AppBar 背景色设置为半透明
九、实现五:毛玻璃底部导航栏
底部导航栏毛玻璃效果实现:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurBottomBarPage extends StatefulWidget {
const BlurBottomBarPage({super.key});
@override
State<BlurBottomBarPage> createState() => _BlurBottomBarPageState();
}
class _BlurBottomBarPageState extends State<BlurBottomBarPage> {
int currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: ListView.builder(
itemCount: 40,
itemBuilder: (context, index) {
return SizedBox(
height: 100,
child: Center(
child: Text('Content $index'),
),
);
},
),
bottomNavigationBar: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 16,
sigmaY: 16,
),
child: BottomNavigationBar(
currentIndex: currentIndex,
backgroundColor: Colors.white.withOpacity(0.2),
elevation: 0,
onTap: (index) {
setState(() {
currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
],
),
),
),
);
}
}
关键点:
- Scaffold 设置
extendBody: true - bottomNavigationBar 外层包裹 BackdropFilter
- BottomNavigationBar 背景色设置半透明
- ClipRect 限制模糊区域
十、实现六:局部遮罩模糊
只模糊某一块区域,如图片底部标题背景:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class LocalBlurCard extends StatelessWidget {
const LocalBlurCard({super.key});
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
Image.asset(
'assets/images/card_bg.jpg',
width: 320,
height: 220,
fit: BoxFit.cover,
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 12,
sigmaY: 12,
),
child: Container(
padding: const EdgeInsets.all(16),
color: Colors.black.withOpacity(0.25),
child: const Text(
'局部底部模糊标题区域',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
),
),
),
],
),
);
}
}
适用场景:
- 视频卡片标题
- 音乐封面信息
- 直播间底部信息
- 图片详情描述
- Banner 文案背景
十一、实现七:隐私内容模糊
手机号、余额、身份证等敏感信息模糊隐藏:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class PrivacyBlurText extends StatelessWidget {
const PrivacyBlurText({
super.key,
required this.visible,
});
final bool visible;
@override
Widget build(BuildContext context) {
final text = const Text(
'¥ 102,400.00',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
);
if (visible) {
return text;
}
return ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 6,
sigmaY: 6,
),
child: text,
);
}
}
使用方式:
dart
PrivacyBlurText(
visible: false,
)
适用场景:
- 余额隐藏
- 手机号隐藏
- 证件号隐藏
- 聊天敏感内容隐藏
- 图片审核前预览隐藏
十二、实现八:动态调节模糊强度
通过 Slider 实时控制模糊程度:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class DynamicBlurPage extends StatefulWidget {
const DynamicBlurPage({super.key});
@override
State<DynamicBlurPage> createState() => _DynamicBlurPageState();
}
class _DynamicBlurPageState extends State<DynamicBlurPage> {
double blur = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('动态高斯模糊'),
),
body: Column(
children: [
Expanded(
child: Center(
child: ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: blur,
sigmaY: blur,
),
child: Image.asset(
'assets/images/bg.jpg',
width: 300,
height: 200,
fit: BoxFit.cover,
),
),
),
),
Slider(
min: 0,
max: 30,
value: blur,
onChanged: (value) {
setState(() {
blur = value;
});
},
),
Text('当前模糊值:${blur.toStringAsFixed(1)}'),
const SizedBox(height: 24),
],
),
);
}
}
项目应用场景:
- 图片编辑器模糊调节
- 背景虚化动画
- 页面滚动时 AppBar 渐进模糊
- 播放器背景跟随状态变化
十三、实现九:滚动时 AppBar 逐渐模糊
页面上滑,AppBar 由透明逐步变成毛玻璃效果:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class ScrollBlurAppBarPage extends StatefulWidget {
const ScrollBlurAppBarPage({super.key});
@override
State<ScrollBlurAppBarPage> createState() => _ScrollBlurAppBarPageState();
}
class _ScrollBlurAppBarPageState extends State<ScrollBlurAppBarPage> {
final ScrollController controller = ScrollController();
double blur = 0;
double opacity = 0;
@override
void initState() {
super.initState();
controller.addListener(() {
final offset = controller.offset;
final progress = (offset / 120).clamp(0.0, 1.0);
setState(() {
blur = 16 * progress;
opacity = 0.25 * progress;
});
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final topPadding = MediaQuery.paddingOf(context).top;
return Scaffold(
body: Stack(
children: [
ListView.builder(
controller: controller,
padding: EdgeInsets.zero,
itemCount: 30,
itemBuilder: (context, index) {
if (index == 0) {
return Image.asset(
'assets/images/header.jpg',
height: 260,
width: double.infinity,
fit: BoxFit.cover,
);
}
return SizedBox(
height: 80,
child: Center(
child: Text('Item $index'),
),
);
},
),
Positioned(
top: 0,
left: 0,
right: 0,
height: topPadding + 56,
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: blur,
sigmaY: blur,
),
child: Container(
padding: EdgeInsets.only(top: topPadding),
color: Colors.white.withOpacity(opacity),
alignment: Alignment.center,
child: const Text(
'详情页',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
],
),
);
}
}
适用场景:
- 商品详情页
- 用户主页
- 图片详情页
- 音乐播放页
- 视频详情页
十四、性能优化建议
高斯模糊视觉效果好,但 GPU 开销大,尤其 BackdropFilter,需做好优化。
1. 必须限制模糊区域
❌ 不推荐(无裁剪,模糊范围过大):
dart
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
child: Container(),
)
✅ 推荐(配合裁剪限定范围):
dart
ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 12,
sigmaY: 12,
),
child: Container(
width: 200,
height: 120,
color: Colors.white.withOpacity(0.2),
),
),
)
2. 优先使用 ImageFiltered 模糊单个组件
模糊单张图片、单个组件,优先用 ImageFiltered,性能更好。
✅ 推荐:
dart
ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Image.asset('assets/images/bg.jpg'),
)
❌ 不推荐:
dart
Stack(
children: [
Image.asset('assets/images/bg.jpg'),
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Container(),
),
],
)
简易选择原则:
- 模糊自己:ImageFiltered
- 模糊背景:BackdropFilter
3. 控制 sigma 大小
建议取值规范:
- 普通毛玻璃:8 - 16
- 背景虚化:12 - 24
- 轻微遮罩:3 - 8
不建议使用 sigma 50+,视觉提升极小,性能开销翻倍。
4. 列表中谨慎使用 BackdropFilter
ListView 每个 Item 都加毛玻璃,极易造成滚动卡顿。
大量毛玻璃场景可使用 BackdropGroup + BackdropFilter.grouped 合并渲染,降低开销。
示例代码:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class GroupedBlurListPage extends StatelessWidget {
const GroupedBlurListPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: BackdropGroup(
child: ListView.builder(
itemCount: 20,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter.grouped(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Container(
height: 80,
alignment: Alignment.center,
color: Colors.white.withOpacity(0.18),
child: Text('Blur Item $index'),
),
),
),
);
},
),
),
);
}
}
注意:多个 BackdropFilter 区域重叠时,不要共用同一个 backdrop key,避免视觉异常。
5. 避免频繁 setState 改变 blur
模糊值随滚动变化时,做节流处理,减少 Widget 重建:
dart
final progress = (offset / 120).clamp(0.0, 1.0);
final newBlur = 16 * progress;
if ((newBlur - blur).abs() > 0.5) {
setState(() {
blur = newBlur;
});
}
十五、常见问题
1. 为什么 BackdropFilter 没有效果?
常见原因:
- 背后没有可模糊的内容
- 没有嵌套在 Stack 中
- child 为空且无固定尺寸
- 未使用 ClipRect / ClipRRect 限制区域
- 前后背景颜色过于接近,看不出模糊
2. 为什么毛玻璃效果不明显?
- 背景是纯色无细节
- 半透明蒙层透明度太低
- blur 模糊值过小
- 背景本身层次感不足
优化:调高 sigma 至 16 左右,同时设置合理半透明背景色。
3. 为什么页面滑动卡顿?
- 模糊区域过大无裁剪
- sigma 数值设置过高
- ListView 大量 Item 使用 BackdropFilter
- 模糊值频繁动态刷新重建
- 未使用 Clip 限制渲染范围
优化:缩小区间、降低 sigma、列表减少使用、静态图片提前预处理模糊。
十六、实际项目推荐封装
封装全能 BlurView,支持圆角、边框、点击事件、自定义背景色:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurView extends StatelessWidget {
const BlurView({
super.key,
required this.child,
this.blur = 12,
this.borderRadius = 16,
this.padding = EdgeInsets.zero,
this.backgroundColor,
this.border,
this.onTap,
});
final Widget child;
final double blur;
final double borderRadius;
final EdgeInsetsGeometry padding;
final Color? backgroundColor;
final BoxBorder? border;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
final radius = BorderRadius.circular(borderRadius);
return ClipRRect(
borderRadius: radius,
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: blur,
sigmaY: blur,
),
child: Material(
color: backgroundColor ?? Colors.white.withOpacity(0.18),
child: InkWell(
onTap: onTap,
child: Container(
padding: padding,
decoration: BoxDecoration(
borderRadius: radius,
border: border,
),
child: child,
),
),
),
),
);
}
}
使用示例:
dart
BlurView(
blur: 16,
borderRadius: 24,
padding: const EdgeInsets.all(20),
border: Border.all(
color: Colors.white.withOpacity(0.3),
),
child: const Text(
'封装后的毛玻璃组件',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
)
十七、完整示例:高斯模糊登录页
综合所有知识点,实现高颜值毛玻璃登录页面:
dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurLoginPage extends StatelessWidget {
const BlurLoginPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: [
Image.asset(
'assets/images/login_bg.jpg',
fit: BoxFit.cover,
),
Container(
color: Colors.black.withOpacity(0.25),
),
Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(28),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 18,
sigmaY: 18,
),
child: Container(
width: 320,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.18),
borderRadius: BorderRadius.circular(28),
border: Border.all(
color: Colors.white.withOpacity(0.3),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Welcome',
style: TextStyle(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 24),
TextField(
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: '请输入账号',
hintStyle: TextStyle(
color: Colors.white.withOpacity(0.7),
),
filled: true,
fillColor: Colors.white.withOpacity(0.12),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide.none,
),
),
),
const SizedBox(height: 16),
TextField(
obscureText: true,
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: '请输入密码',
hintStyle: TextStyle(
color: Colors.white.withOpacity(0.7),
),
filled: true,
fillColor: Colors.white.withOpacity(0.12),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide.none,
),
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 48,
child: ElevatedButton(
onPressed: () {},
child: const Text('登录'),
),
),
],
),
),
),
),
),
],
),
);
}
}
十八、总结
Flutter 高斯模糊核心依赖:
dart
ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
)
两大核心组件区别:
- ImageFiltered:模糊自身子组件(图片、文字、头像、隐私遮挡)
- BackdropFilter:模糊底层背景(毛玻璃卡片、AppBar、底部导航、弹窗背景)
项目实践核心要点:
- 毛玻璃必须配合
ClipRect/ClipRRect限定范围 - 禁止 BackdropFilter 无限制全屏模糊
- sigma 常规控制在 8-16,兼顾颜值与性能
- ListView 列表慎用 BackdropFilter,可用 BackdropGroup 优化
- 静态图片模糊优先用 ImageFiltered,减少实时 GPU 渲染压力
- 复杂页面模糊效果可提前图片预处理,降低页面卡顿风险
高斯模糊能大幅提升界面质感,但需平衡视觉表现、组件封装、渲染性能,才是专业的 Flutter 开发实现方案。