如何用Canvas实现BackdropFilter同款模糊效果?
用Canvas复刻BackdropFilter模糊效果的问题
我想在Flutter里用Canvas实现和BackdropFilter完全一致的模糊效果,参考的BackdropFilter实现代码如下:
ClipRect( child: BackdropFilter( filter: ui.ImageFilter.blur(sigmaX: 15, sigmaY: 15), child: Container( width: 300, height: 300, ), ), ),
我自己写的Canvas实现代码是这样的:
Paint paint = Paint() ..color = Colors.white ..imageFilter = ui.ImageFilter.blur(sigmaX: 15, sigmaY: 15) ..blendMode = BlendMode.srcOver;
但两种方式的效果完全不一样:
BackdropFilter的效果:
Canvas Paint的效果:
问题原因
BackdropFilter的逻辑是先模糊它下方的所有内容(背景),再在模糊后的背景上绘制透明容器;而你直接给Paint加imageFilter,是对当前绘制的白色矩形本身进行模糊——相当于把实心白色块模糊成扩散的灰色,和BackdropFilter的逻辑完全相反。
正确的Canvas实现方式
要复刻BackdropFilter的效果,需要先捕获要模糊的背景区域,对其模糊后再绘制到Canvas上,最后叠加透明容器:
- 先用
RepaintBoundary包裹需要模糊的背景内容,通过GlobalKey捕获它:
final repaintKey = GlobalKey(); // 在Widget树中包裹背景 RepaintBoundary( key: repaintKey, child: // 你的背景内容(比如页面上的其他组件) )
- 在CustomPainter的
paint方法中,捕获背景图像并绘制模糊效果:
class CustomBlurPainter extends CustomPainter { final GlobalKey repaintKey; CustomBlurPainter(this.repaintKey); @override Future<void> paint(Canvas canvas, Size size) async { // 获取背景渲染对象并转换为图像 final boundary = repaintKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; final backgroundImage = await boundary?.toImage(); if (backgroundImage == null) return; // 创建模糊画笔 final blurPaint = Paint() ..imageFilter = ui.ImageFilter.blur(sigmaX: 15, sigmaY: 15); // 绘制模糊后的背景(只绘制需要的300x300区域) final blurRect = Rect.fromLTWH(0, 0, 300, 300); canvas.drawImageRect( backgroundImage, blurRect, // 从背景中截取的区域 blurRect, // 绘制到Canvas的位置 blurPaint, ); // 叠加透明容器(和BackdropFilter中的Container对应,注意要加透明度) canvas.drawRect( blurRect, Paint()..color = Colors.white.withOpacity(0.5), ); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }
这样就能实现和BackdropFilter完全一致的模糊效果了——先模糊背景区域,再在上面叠加半透明白色容器。
内容的提问来源于stack exchange,提问作者giordy16
相关产品推荐
相关产品推荐

