如今應該不少地方都會使用到高斯模糊的效果,想當初在Android上實現差點沒要了個人老命,那麼在 Flutter 中實現會是如何?git
Flutter 提供了 BackdropFilter 來實現高斯模糊的效果,照例打開源碼:github
class BackdropFilter extends SingleChildRenderObjectWidget {
/// Creates a backdrop filter.
///
/// The [filter] argument must not be null.
const BackdropFilter({
Key key,
@required this.filter,
Widget child,
}) : assert(filter != null),
super(key: key, child: child);
/// The image filter to apply to the existing painted content before painting the child.
///
/// For example, consider using [ImageFilter.blur] to create a backdrop
/// blur effect
final ui.ImageFilter filter;
}
複製代碼
能夠看到必需要傳一個 ImageFilter filter
,並且註釋上也寫了markdown
For example, consider using [ImageFilter.blur] to create a backdrop blur effectapp
例如,考慮使用 ImageFilter.blur 來講建立一個背景模糊的效果。less
並且,在類的上面還有很長的一段註釋:ide
/// A widget that applies a filter to the existing painted content and then
/// paints [child].
///
/// The filter will be applied to all the area within its parent or ancestor
/// widget's clip. If there's no clip, the filter will be applied to the full
/// screen.
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=dYRs7Q1vfYI}
///
/// {@tool sample}
/// If the [BackdropFilter] needs to be applied to an area that exactly matches
/// its child, wraps the [BackdropFilter] with a clip widget that clips exactly
/// to that child.
///
/// ```dart
/// Stack(
/// fit: StackFit.expand,
/// children: <Widget>[
/// Text('0' * 10000),
/// Center(
/// child: ClipRect( // <-- clips to the 200x200 [Container] below
/// child: BackdropFilter(
/// filter: ui.ImageFilter.blur(
/// sigmaX: 5.0,
/// sigmaY: 5.0,
/// ),
/// child: Container(
/// alignment: Alignment.center,
/// width: 200.0,
/// height: 200.0,
/// child: Text('Hello World'),
/// ),
/// ),
/// ),
/// ),
/// ],
/// )
/// ```
複製代碼
最前面一段話說的是:若是你不設置他大小的話,這個組件將是全屏的。函數
而後!他放出來了一個 YouTube 的視頻!還有一段Demoui
那話很少說,咱們直接運行官方給出來的Demo,看看是什麼效果:this
當這一大串 0 顯示在我眼前的時候我差點瞎了。spa
不過能夠看到使用 BackdropFilter 很是簡單就實現了高斯模糊的效果。
那咱們能夠按照Demo的思路來封裝幾個背景是高斯模糊的控件:
class BlurOvalWidget extends StatelessWidget {
final Widget _widget;
double _padding = 10;
BlurOvalWidget(this._widget, {double padding = 0}) {
if (padding != 0) this._padding = padding;
}
@override
Widget build(BuildContext context) {
return ClipOval(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Container(
color: Colors.white10,
padding: EdgeInsets.all(_padding),
child: _widget,
),
),
);
}
}
複製代碼
咱們使用的是無狀態的小部件,構造函數裏須要傳入一個widget,用來放在模糊的背景上面。
而後咱們的build 方法直接返回一個圓形的模糊背景,橫縱向模糊的數值爲10,值越大,模糊的效果就越大。
不能光有圓形的模糊背景,再來一個圓角矩形的:
class BlurRectWidget extends StatelessWidget {
final Widget _widget;
double _padding = 10;
BlurRectWidget(this._widget, {double padding = 0}) {
if (padding != 0) this._padding = padding;
}
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 50),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 20,
sigmaY: 20,
),
child: Container(
color: Colors.white10,
padding: EdgeInsets.all(_padding),
child: _widget,
),
),
),
);
}
}
複製代碼
代碼基本同樣,只不過就是把 ClipOval 換成了 ClipRRect
如今咱們用封裝好的兩個 widget 來實現一個比較簡單的頁面:
上面的文字用到了咱們定義的圓角矩形,下面的用到了咱們定義的圓形。
代碼以下,比較簡單,就是普通的搭建頁面:
class _BackdropFilterPageState extends State<BackdropFilterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BackdropFilterPageState'),
),
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
'images/bg.jpg',
fit: BoxFit.cover,
),
Center(
child: BlurRectWidget(
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'BackdropFilter class',
style: TextStyle(
fontSize: 16,
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text(
'A widget that applies a filter to the existing painted content and then paints child.'
'The filter will be applied to all the area within its parent or ancestor widget\'s clip. If there\'s no clip, the filter will be applied to the full screen.',
style: TextStyle(fontSize: 14, color: Colors.black87),
textAlign: TextAlign.justify,
),
),
],
),
),
),
Container(
alignment: Alignment.bottomCenter,
margin: EdgeInsets.only(bottom: 150),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
BlurOvalWidget(
IconButton(
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context){
return BlurImagePage();
}));
},
icon: Icon(
Icons.favorite,
color: Colors.white,
),
iconSize: 30,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 50.0),
child: BlurOvalWidget(
Icon(
Icons.share,
color: Colors.white,
size: 30,
),
),
),
BlurOvalWidget(
Icon(
Icons.bookmark,
color: Colors.white,
size: 30,
),
),
],
),
),
],
),
);
}
}
複製代碼
那這個時候就有人問了,只能把模糊放在背景裏嗎,不能用來當前景嗎?
固然能夠,否則我還費這麼多話幹什麼?
先看一下效果圖:
怎麼樣,是否是你要的感受🌝,有沒有一種想要充錢的衝動!
固然,這種效果實現起來也是很是的簡單,咱們只須要把 BackdropFilter 的 child 設置爲一個 Container(),而且設置上顏色(我這裏使用的是 Colors.white10),而後放在 Stack 中就ok啦。
代碼以下:
class BlurImagePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child: Image.asset(
'images/wanimal.png',
fit: BoxFit.cover,
),
),
Positioned.fill(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 15,
sigmaY: 15,
),
child: Container(
color: Colors.white10,
),
),
),
RaisedButton(
textColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))),
color: Colors.orangeAccent,
child: Text('充錢查看更多', style: TextStyle(fontSize: 16),),
onPressed: (){},
)
],
)),
);
}
}
複製代碼
先放咱們須要被遮住的 widget,而後放上咱們的模糊 widget,再而後就可讓用戶充錢了。
BackdropFilter 不單單隻能夠作高斯模糊的效果,也能夠用來作旋轉,傾斜等。
只不過咱們經常使用的是高斯模糊,其原理同樣。
瞭解更多能夠移步 Flutter 官網:flutter.dev/
原文代碼移步Giuhub:github.com/wanglu1209/…
圖我就不傳了,23333.