??????小菜在學(xué)習(xí)時(shí)想要做一點(diǎn)類(lèi)似毛玻璃的效果,首先想到的是高斯模糊,對(duì)于原生 Android 需要話費(fèi)很多精力,而 Flutter 提供了 BackdropFilter 高斯模糊的 Widget,真的很方便;

源碼分析
const BackdropFilter({
Key key,
@required this.filter,
Widget child
})
??????分析源碼,必須要傳遞 filter 參數(shù),用來(lái)構(gòu)建模糊層效果;小菜理解只是通過(guò) BackdropFilter 構(gòu)建一個(gè)模糊圖層,借助 Stack 等設(shè)置圖層是在上層或下層,官方也推薦了 DecoratedBox 設(shè)置圖層上下;
??????模糊圖層通常借用 ImageFilter.blur 設(shè)置模糊度,一般是在 0.0-10.0 之間,數(shù)值越大模糊度越高,超過(guò) 10.0 時(shí)完全不可見(jiàn);
??????小菜在設(shè)置模糊顏色時(shí)嘗試了 withOpacity 方法,一般是在 0.0-1.0 之間,用來(lái)設(shè)置顏色值的透明度;也可以采用 withAlpha 方法,效果相同,一般是在 0-255 之間;同時(shí)還可以采用 withRed / withGreen / withBlue 直接設(shè)置三原色的基礎(chǔ)值實(shí)現(xiàn)不同效果;
Widget _imageBackWid() {
return Center(
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Row(children: <Widget>[
_itemWid(Colors.red.withOpacity(0.1), 4.0),
_itemWid(Colors.white.withOpacity(0.1), 8.0),
]),
Row(children: <Widget>[
_itemWid(Colors.white.withOpacity(0.1), 4.0),
Container(
width: MediaQuery.of(context).size.width * 0.5,
height: MediaQuery.of(context).size.width * 0.5,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 4.0, sigmaY: 4.0),
child: Container(
color: Colors.white.withOpacity(0.1),
child: Padding(
padding: EdgeInsets.all(14.0),
child: Image.asset('images/icon_hzw01.jpg')))))
])
]));
}
Widget _itemWid(color, blur) {
return Container(
width: MediaQuery.of(context).size.width * 0.5,
height: MediaQuery.of(context).size.width * 0.5,
child: Stack(children: <Widget>[
Padding(
padding: EdgeInsets.all(14.0),
child: Image.asset('images/icon_hzw01.jpg')),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
child: Container(color: color))
]));
}

??????小菜嘗試了一個(gè)很不完善的小案例,類(lèi)似于查看截圖的小窗口,遮罩層是模糊圖層;小菜用了很蠢的方式來(lái)處理,底部是一個(gè)設(shè)置了高斯模糊的背景圖,上層通過(guò) Canvas 展示一張完全相同的圖片,借用 drawImage 實(shí)現(xiàn)小窗口,再通過(guò)手指坐標(biāo)控制窗口位置;未對(duì)機(jī)型適配,僅作為一個(gè)不完善的小測(cè)試案例;
??????小菜附上核心代碼僅供參考,若有更好的方法請(qǐng)多多指導(dǎo)!
class BackDropCanvas extends CustomPainter {
ui.Image background;
BuildContext context;
var dx = 0.0, dy = 0.0;
static const double smallScan = 200.0;
BackDropCanvas(this.context, this.background, this.dx, this.dy);
@override
void paint(Canvas canvas, Size size) {
canvas.clipPath(Path()
..moveTo((Screen.width - smallScan) * 0.5 + dx,
(Screen.height - smallScan) * 0.5 + dy)
..lineTo((Screen.width + smallScan) * 0.5 + dx,
(Screen.height - smallScan) * 0.5 + dy)
..lineTo((Screen.width + smallScan) * 0.5 + dx,
(Screen.height + smallScan) * 0.5 + dy)
..lineTo((Screen.width - smallScan) * 0.5 + dx,
(Screen.height + smallScan) * 0.5 + dy));
canvas.drawImage(this.background, ui.Offset.zero, Paint());
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class _BackedDropPage extends State<BackedDropPage> {
ui.Image _background;
bool _prepDone;
var dx = 0.0, dy = 0.0;
static const double smallScan = 200.0;
@override
void initState() {
_prepDone = false;
super.initState();
_prepare();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: <Widget>[
Container(
width: Screen.width,
height: Screen.height,
child: Stack(children: <Widget>[
Center(child: Image.asset('images/icon_hzw04_1.jpg')),
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 4.0, sigmaY: 4.0),
child: Container(color: Colors.black.withOpacity(0.2)))
])),
_prepDone
? Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: CustomPaint(
painter: BackDropCanvas(context, _background, dx, dy)))
: Container(color: Colors.grey),
GestureDetector(onPanUpdate: (d) {
if (d.globalPosition.dx >= smallScan * 0.5 &&
d.globalPosition.dx <= Screen.width - smallScan * 0.5) {
dx = d.globalPosition.dx - Screen.width * 0.5;
}
if (d.globalPosition.dy >= smallScan * 0.5 &&
d.globalPosition.dy <= Screen.height - smallScan * 0.5) {
dy = d.globalPosition.dy - Screen.height * 0.5;
}
setState(() {});
})
]));
}
_prepare() {
loadImage('images/icon_hzw04_1.jpg').then((image) {
_background = image;
}).whenComplete(() {
_prepDone = true;
setState(() {});
});
}
}

??????BackdropFilter 高斯模糊是一個(gè)實(shí)用且方便的 Widget,可靈活應(yīng)用在項(xiàng)目中;小菜對(duì)此研究還不夠深入,有問(wèn)題的話請(qǐng)多多指導(dǎo)!
來(lái)源:阿策小和尚