注册

App高级感营造之 高斯模糊

效果


类似毛玻璃,或者马赛克的效果。我们可以用它来提升app背景的整体质感,或者给关键信息打码。


高斯模糊1.gif


高斯模糊2.gif


源代码


import 'dart:ui';

import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});

final String title;

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
// 高斯模糊的第一种写法 ImageFiltered 包裹要模糊的组件

/// 将子组件进行高斯模糊
/// [child] 要模糊的子组件
Widget _imageFilteredWidget1({required Widget child, double sigmaValue = 1}) {
return ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: sigmaValue, sigmaY: sigmaValue),
child: child,
);
}

/// 使用第一种模糊方式的案例
Widget _demo1() {
return Container(
padding: const EdgeInsets.all(50),
color: Colors.blue.shade100,
width: double.infinity,
child: Column(
children: [
_imageFilteredWidget1(
child: SizedBox(
width: 150,
child: Image.asset(
"assets/images/bz1.jpg",
fit: BoxFit.fitHeight,
),
),
),
const SizedBox(height: 100),
_imageFilteredWidget1(
child: const Text(
"测试高斯模糊",
style: TextStyle(fontSize: 30, color: Colors.blueAccent),
),
sigmaValue: 2)
],
),
);
}

/// 利用 BackdropFilter 做高斯模糊
_backdropFilterWidget2({
required Widget child,
double sigmaValueX = 1,
double sigmaValueY = 1,
}) {
return ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: sigmaValueX, sigmaY: sigmaValueY),
child: child,
),
);
}

///
Widget _demo2() {
return SizedBox(
width: double.infinity,
height: double.infinity,
child: Stack(
alignment: Alignment.center,
children: [
Positioned.fill(
child: Image.asset(
"assets/images/bz1.jpg",
fit: BoxFit.fill,
),
),
Positioned(
child: _backdropFilterWidget2(
sigmaValueX: _sigmaValueX,
sigmaValueY: _sigmaValueY,
child: Container(
width: MediaQuery.of(context).size.width - 100,
height: MediaQuery.of(context).size.height / 2,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0x90ffffff),
),
child: const Text(
"高斯模糊",
style: TextStyle(fontSize: 30, color: Colors.white),
),
)),
top: 20,
),
_slider(
bottomMargin: 200,
themeColors: Colors.yellow,
title: '横向模糊度',
valueAttr: _sigmaValueX,
onChange: (double value) {
setState(() {
_sigmaValueX = value;
});
},
),
_slider(
bottomMargin: 160,
themeColors: Colors.blue,
title: '纵向模糊度',
valueAttr: _sigmaValueY,
onChange: (double value) {
setState(() {
_sigmaValueY = value;
});
},
),
_slider(
bottomMargin: 120,
themeColors: Colors.green,
title: '同时调整:',
valueAttr: _sigmaValue,
onChange: (double value) {
setState(() {
_sigmaValue = value;
_sigmaValueX = value;
_sigmaValueY = value;
});
},
),
],
),
);
}

Widget _slider({
required String title,
required double bottomMargin,
required Color themeColors,
required double valueAttr,
required ValueChanged<double>? onChange,
}) {
return Positioned(
bottom: bottomMargin,
child: Row(
children: [
Text(title, style: TextStyle(color: themeColors, fontSize: 18)),
SliderTheme(
data: SliderThemeData(
trackHeight: 20,
activeTrackColor: themeColors.withOpacity(.7),
thumbColor: themeColors,
inactiveTrackColor: themeColors.withOpacity(.4)
),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: Slider(
value: valueAttr,
min: 0,
max: 10,
onChanged: onChange,
),
),
),
SizedBox(
width: 50,
child: Text('${valueAttr.round()}',
style: TextStyle(color: themeColors, fontSize: 18)),
),
],
),
);
}

double _sigmaValueX = 10;
double _sigmaValueY = 10;

double _sigmaValue = 10;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _demo2(),
);
}
}

实现原理


实现高斯模糊,在flutter中有两种方式:


ImageFiltered


它可以对其包裹的子组件施加高斯模糊,需要传入 ImageFilter 控制模糊程度,分为X Y两个方向的模糊,实际上就是对图片进行拉伸,数字越大,模糊效果越大。


/// 将子组件进行高斯模糊
/// [child] 要模糊的子组件
Widget _imageFilteredWidget1({required Widget child, double sigmaValue = 1}) {
return ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: sigmaValue, sigmaY: sigmaValue),
child: child,
);
}

BackDropFilter


同样需要一个 ImageFilter参数控制模糊度,与 ImageFilter的区别是,它会对它覆盖的组件整体模糊。
所以如果我们需要对指定的子组件进行模糊的话,需要再包裹一个ClipRect裁切。


/// 利用  BackdropFilter 做高斯模糊
_backdropFilterWidget2({required Widget child, double sigmaValue = 1}) {
return ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaY: sigmaValue, sigmaX: sigmaValue),
child: child,
),
);
}

由于 BackdropFilter 会对其子组件进行图形处理,所以其子组件可能会变得更加消耗性能。因此,需要谨慎使用 BackdropFilter 组件。


作者:拳布离手
来源:juejin.cn/post/7239631010429108280

0 个评论

要回复文章请先登录注册