Flutter 實現背景圖片毛玻璃效果

語言: CN / TW / HK

theme: v-green highlight: atom-one-dark


持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第4天,點選檢視活動詳情

前言

繼續我們繪圖相關篇章,這次我們來看看如何使用 CustomPaint 實現毛玻璃背景圖效果。毛玻璃背景圖其實就是將圖片進行一定程度的模糊,背景圖經過模糊後更加虛幻,使得前景和後景就會有層次感。相比直接加蒙層的效果來說,毛玻璃看起來更加好看一些。下面是背景圖處理前後的對比,我們的前景圖片的透明度並沒有改變,但是背景圖模糊虛化後,感覺前景更加顯眼了一樣。 模糊前後對比.jpg 本篇涉及如下內容:

  • 使用 canvas 繪製圖片。
  • 繪製圖片時如何更改圖片的填充範圍。
  • 使用 ImageFilter 模糊圖片,實現毛玻璃效果。

使用 canvas 繪製圖片

Flutter 為 canvas 提供了drawImage 方法用於繪製圖片,方法定義如下: dart void drawImage(Image image, Offset offset, Paint paint) 其中各個引數說明如下:

  • imagedart:ui中的 Image 物件,注意不是Widget 中的 Image,因此繪製的時候需要將圖片資源轉換為 ui.Image 物件。下面是轉換的示例程式碼,fillImage 即最終得到的 ui.Image 物件。注意轉換需要一定的時間,因此需要使用非同步 async / await 操作。 ```dart Future init() async { final ByteData data = await rootBundle.load('images/island-coder.png'); fillImage = await loadImage(Uint8List.view(data.buffer)); }

Future loadImage(Uint8List img) async { final Completer 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,定義如下: dart 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物件。方法定義如下: dart factory ImageFilter.blur({ double sigmaX = 0.0, double sigmaY = 0.0, TileMode tileMode = TileMode.clamp }) 這個方法實際呼叫的是一個高斯模糊處理器,高斯模糊其實就是應用一個方法將畫素點周邊指定範圍的值進行處理,進而實現模糊效果,有興趣的可以自行百度一下。下面的 sigmaXsigmaY 分佈代表橫軸方向和縱軸方向的模糊程度,數值越大,模糊程度越厲害。因此我們可以通過這兩個引數控制模糊程度。 dart return _GaussianBlurImageFilter( sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode ); 注意,這裡 sigmaX 和 sigmaY 不能同時為0,否則會報錯!這裡應該是如果同時為0會導致除0操作。 下面來看整體的繪製實現程式碼,如下所示: ```dart 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方法確保圖片填充滿整個背景。完整程式碼已經提交至:[繪圖相關程式碼](https://gitee.com/island-coder/flutter-beginner/tree/master/custom_paint),檔名為:blur_image_demo.dart`。變換模糊值的效果如下動圖所示。 背景圖模糊過程.gif

總結

本篇介紹了使用 CustomPaint 實現背景圖模糊,毛玻璃的效果。關鍵點在於 使用 Paint 物件的 imageFilter屬性,使用高斯模糊應用到圖片上。以後碰到需要模糊背景圖的地方就可以直接上手用啦!

我是島上碼農,微信公眾號同名,這是Flutter 入門與實戰的專欄文章,提供體系化的 Flutter 學習文章。對應原始碼請看這裡:Flutter 入門與實戰專欄原始碼。如有問題可以加本人微信交流,微訊號:island-coder

👍🏻:覺得有收穫請點個贊鼓勵一下!

🌟:收藏文章,方便回看哦!

💬:評論交流,互相進步!