寫在前面
Flutter中的高斯模糊(毛玻璃)大家應(yīng)該都不陌生,我們可以用它實現(xiàn)畫中畫,閱后即焚渔扎,付費看高清等功能沮趣,是常用的UI組件肚吏。目前我正在做的項目中使用的點是 閱后即焚 IM中發(fā)送圖片的功能
先放一張圖
實現(xiàn)頁面
通常處理
Stack(
children: [
CachedNetworkImage(imageUrl: path, fit: BoxFit.cover, width: width, height: height),
Container(
alignment: Alignment.center,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10.fit)),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(color: Colors.white.withAlpha(0)),
),
),
],
)
很簡單 就實現(xiàn)了我們想要的效果成福,到這里就完了嗎橡类,也不是 我們滑動頁面debug模式先會明顯看到頁面的卡頓桥滨,這是我們所不允許的笼蛛,使用DevTools看滑動過程中的看繪制情況
2個圖片的繪制情況
系統(tǒng)filter繪制情況
優(yōu)化
上圖我們發(fā)現(xiàn)滑動過程中繪制情況不容樂觀 這也是出現(xiàn)卡頓的原因
那有沒有別的方法呢洒放,當(dāng)然有,看具體代碼
Widget _blur(double width, double height) {
loadNetImage(msg.image?.remotePath ?? '');
return Obx(
() => image.value != null
? CustomPaint(
size: Size(width, height), painter: GlassPainter(image.value!, Size(image.value!.width.toDouble(), image.value!.height.toDouble())))
: Container(),
);
return Container(
alignment: Alignment.center,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10.fit)),
child: BackdropFilter(
filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(color: Colors.white.withAlpha(0)),
),
);
}
// 這里是加載的網(wǎng)絡(luò)圖片 同樣可以換為本地圖片或是加載file文件
Future loadNetImage(String path) async {
final data = await NetworkAssetBundle(Uri.parse(path)).load(path);
final bytes = data.buffer.asUint8List();
final imageD = await decodeImageFromList(bytes);
image.value = imageD;
}
class GlassPainter extends CustomPainter {
final ui.Image image;
final Size imageSize;
final Paint _paint = Paint()
..color = Colors.white.withOpacity(0.8)
..style = PaintingStyle.fill
..imageFilter = ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10, tileMode: TileMode.decal);
GlassPainter(this.image, this.imageSize);
@override
void paint(Canvas canvas, Size size) {
final Rect rect = Offset.zero & size;
canvas.drawImageRect(image, Rect.fromLTWH(0, 0, imageSize.width, imageSize.height), rect, _paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
加載本地、file滨砍、相冊圖片
// 本地資源圖片
Future loadIamge(String path) async {
// 加載資源文件
final data = await rootBundle.load(path);
// 把資源文件轉(zhuǎn)換成Uint8List類型
final bytes = data.buffer.asUint8List();
// 解析Uint8List類型的數(shù)據(jù)圖片
final image = await decodeImageFromList(bytes);
this.image = image;
setState(() {});
}
// 可繪制對象
Future loadLocalImage(String path) async {
// 通過字節(jié)的方式讀取本地文件
final bytes = await File(path).readAsBytes();
// 解析圖片資源
final image = await decodeImageFromList(bytes);
this.image = image;
setState(() {});
}
看代碼 我們發(fā)現(xiàn) 我們不使用系統(tǒng)提供給我們的封裝好的組件 我們選擇了 自己去繪制圖片同時設(shè)置畫筆的高斯模糊效果往湿,同樣是兩個圖片 看滑動的性能
優(yōu)化后
優(yōu)化后 滑動明顯好了很多,這只是兩個圖片 若是列表存在更多圖片的話 這種優(yōu)化會更明顯
寫在最后
性能有一個不小的提升 但是有個小問題 圖片沒有做緩存 這里還需要自己對圖片進行緩存處理 防止多次下載同一張圖片
據(jù)說Flutter版本3.22 對 ImageFillter性能做了優(yōu)化惋戏,目前我還沒有測試
有測試過的小伙伴 或是有更優(yōu)化方法 歡迎交流