注册

Flutter 实现背景图片毛玻璃效果

前言


继续我们绘图相关篇章,这次我们来看看如何使用 CustomPaint 实现毛玻璃背景图效果。毛玻璃背景图其实就是将图片进行一定程度的模糊,背景图经过模糊后更加虚幻,使得前景和后景就会有层次感。相比直接加蒙层的效果来说,毛玻璃看起来更加好看一些。下面是背景图处理前后的对比,我们的前景图片的透明度并没有改变,但是背景图模糊虚化后,感觉前景更加显眼了一样。
模糊前后对比.jpg
本篇涉及如下内容:



  • 使用 canvas 绘制图片。
  • 绘制图片时如何更改图片的填充范围。
  • 使用 ImageFilter 模糊图片,实现毛玻璃效果。

使用 canvas 绘制图片


Flutter 为 canvas 提供了drawImage 方法用于绘制图片,方法定义如下:


void drawImage(Image image, Offset offset, Paint paint)

其中各个参数说明如下:



  • imagedart: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 the dst argument.
翻译:通过 src 参数将给定图片的局部(subset)绘制到坐标轴对齐的目标矩形区域内。



下面是我们将源矩形框设置为实际图片的尺寸和一半宽高的对比图,可以看到取一半宽高的只绘制了左上角的1/4区域。实际我们可以定位起始位置来截取部分区域绘制。
截取原图的一半宽高.jpg


毛玻璃效果实现


毛玻璃效果实现和我们上两篇使用 paintshader属性有点类似,Paint 类提供了一个imageFilter属性专门用于图片处理,其中dart:ui 中就提供了ui.ImageFilter.blur方法构建模糊效果处理的 ImageFilter对象。方法定义如下:


factory ImageFilter.blur({ 
double sigmaX = 0.0,
double sigmaY = 0.0,
TileMode tileMode = TileMode.clamp
})

这个方法实际调用的是一个高斯模糊处理器,高斯模糊其实就是应用一个方法将像素点周边指定范围的值进行处理,进而实现模糊效果,有兴趣的可以自行百度一下。下面的 sigmaXsigmaY 分布代表横轴方向和纵轴方向的模糊程度,数值越大,模糊程度越厉害。因此我们可以通过这两个参数控制模糊程度。


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。变换模糊值的效果如下动图所示。
背景图模糊过程.gif


总结


本篇介绍了使用 CustomPaint 实现背景图模糊,毛玻璃的效果。关键点在于 使用 Paint 对象的 imageFilter属性,使用高斯模糊应用到图片上。以后碰到需要模糊背景图的地方就可以直接上手用啦!


作者:岛上码农
链接:https://juejin.cn/post/7113131636195065892
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册