目录
前言
继续我们绘图相关篇章,这次我们来看看如何使用 CustomPaint 实现毛玻璃背景图效果。毛玻璃背景图其实就是将图片进行一定程度的模糊,背景图经过模糊后更加虚幻,使得前景和后景就会有层次感。相比直接加蒙层的效果来说,毛玻璃看起来更加好看一些。下面是背景图处理前后的对比,我们的前景图片的透明度并没有改变,但是背景图模糊虚化后,感觉前景更加显眼了一样。
本篇涉及如下内容:
- 使用 canvas 绘制图片。
- 绘制图片时如何更改图片的填充范围。
- 使用 ImageFilter 模糊图片,实现毛玻璃效果。
使用 canvas 绘制图片
Flutter 为 canvas
提供了drawImage
方法用于绘制图片,方法定义如下:
void drawImage(Image image, Offset offset, Paint paint)
其中各个参数说明如下:
image
:dart:ui
中的Image
对象,注意不是Widget
中的Image
,因此绘制的时候需要将图片资源转换为ui.Image
对象。下面是转换的示例代码,fillImage 即最终得到的ui.Image
对象。注意转换需要一定的时间,因此需要使用异步async
/await
操作。
Future<void> init() async { final ByteData data = await rootBundle.load('images/island-coder.png'); fillImage = await loadImage(Uint8List.view(data.buffer)); } Future<ui.Image> loadImage(Uint8List img) async { final Completer<ui.Image> completer = Completer(); ui.decodeImageFromList(img, (ui.Image img) { setState(() { isImageLoaded = true; }); return completer.complete(img); }); return completer.future; }
offset
:绘制图片的起始位置。paint
:绘图画笔对象,在paint
上可以应用各种处理效果,比如本篇要用到的图片模糊效果。
注意,drawImage
方法无法更改图片绘制的区域大小,默认就是按图片的实际尺寸绘制的,所以如果要想保证全屏的背景图,我们就需要使用另一个绘制图片的方法。
更改绘制图片的绘制范围
Flutter 的 canvas
为绘制图片提供了一个尺寸转换方法,即可以通过指定原绘制区域的矩形和目标区域的矩形,将图片某个区域映射到新的矩形框中绘制。也就是我们甚至可以实现绘制图片的局部区域。该方法名为 drawImageRect
,定义如下:
void drawImageRect(Image image, Rect src, Rect dst, Paint paint)
方法的参数比较容易懂,我们来看看 Flutter 的文档说明。
Draws the subset of the given image described by the
src
argument into the canvas in the axis-aligned rectangle given by thedst
argument. 翻译:通过 src 参数将给定图片的局部(subset)绘制到坐标轴对齐的目标矩形区域内。
下面是我们将源矩形框设置为实际图片的尺寸和一半宽高的对比图,可以看到取一半宽高的只绘制了左上角的1/4区域。实际我们可以定位起始位置来截取部分区域绘制。
毛玻璃效果实现
毛玻璃效果实现和我们上两篇使用 paint
的 shader
属性有点类似,Paint 类提供了一个imageFilter
属性专门用于图片处理,其中dart:ui
中就提供了ui.ImageFilter.blur
方法构建模糊效果处理的 ImageFilter
对象。方法定义如下:
factory ImageFilter.blur({ double sigmaX = 0.0, double sigmaY = 0.0, TileMode tileMode = TileMode.clamp })
这个方法实际调用的是一个高斯模糊处理器,高斯模糊其实就是应用一个方法将像素点周边指定范围的值进行处理,进而实现模糊效果,有兴趣的可以自行百度一下。下面的 sigmaX
和 sigmaY
分布代表横轴方向和纵轴方向的模糊程度,数值越大,模糊程度越厉害。因此我们可以通过这两个参数控制模糊程度。
return _GaussianBlurImageFilter( sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode );
**注意,这里 sigmaX 和 sigmaY 不能同时为0,否则会报错!**这里应该是如果同时为0会导致除0操作。 下面来看整体的绘制实现代码,如下所示:
class BlurImagePainter extends CustomPainter { final ui.Image bgImage; final double blur; BlurImagePainter({ required this.bgImage, required this.blur, }); @override void paint(Canvas canvas, Size size) { var paint = Paint(); // 模糊的取值不能为0,为0会抛异常 if (blur > 0) { paint.imageFilter = ui.ImageFilter.blur( sigmaX: blur, sigmaY: blur, tileMode: TileMode.mirror, ); } canvas.drawImageRect( bgImage, Rect.fromLTRB(0, 0, bgImage.width.toDouble(), bgImage.height.toDouble()), Offset.zero & size, paint, ); }
代码其实很短,就是在模糊值不为0的时候,应用 imageFilter
进行模糊处理,然后使用 drawImageRect
方法确保图片填充满整个背景。完整代码已经提交至:绘图相关代码,文件名为:blur_image_demo.dart
。变换模糊值的效果如下动图所示。
总结
本篇介绍了使用 CustomPaint 实现背景图模糊,毛玻璃的效果。关键点在于 使用 Paint
对象的 imageFilter
属性,使用高斯模糊应用到图片上。以后碰到需要模糊背景图的地方就可以直接上手用啦!