Flutter 中 ColorFiltered、ImageFiltered、BackdropFilter的使用详解 | Flutter Widgets
前言
之前我们聊过 Image ,聊过给图片设置颜色,以及各种混合算法的使用,今天我们聊聊 Flutter 中各种过滤器的使用详解。
ColorFiltered(颜色过滤器)
看名字就知道是增加颜色滤镜效果的,下面先回忆一下我们之前聊的 Image 中设置颜色。
- 一张正常的图片
Image.asset(
'assets/images/img_03.jpeg',
width: 375,
height: 240,
fit: BoxFit.cover,
)
- 设置一个颜色
Image.asset(
'assets/images/img_03.jpeg',
width: 375,
height: 240,
fit: BoxFit.cover,
color: Colors.pink,
)
- 设置混合模式
Image.asset(
'assets/images/img_03.jpeg',
width: 375,
height: 240,
fit: BoxFit.cover,
color: Colors.pink,
colorBlendMode: BlendMode.color,
)
最终我们就合成一张这样带滤镜效果
追踪源码
我我们持续追踪源码到
RenderImage
类中,可以看到最终也是创建了一个 ColorFilter
。
简单使用
上面只是对 Image 增加滤镜效果,如果我们要对 Widget 增加滤镜效果呢?这时就需要用到 ColorFiltered
了,下面我们看看怎么使用吧
ColorFiltered(
// 添加颜色过滤器
colorFilter: ColorFilter.mode(
// 设置颜色
Colors.grey,
// 设置混合模式
BlendMode.saturation,
),
child: ImageDescWidget(),
)
滤镜前 | 滤镜后 | 滤镜后-粉色 |
---|---|---|
![]() | ![]() | ![]() |
其他构建方法
除了 ColorFilter.mode
我们如果翻看 ColorFilter
的源码,还会发现如下的几种构建方法
- ColorFilter.linearToSrgbGamma()
构造一个将 sRGB 伽马曲线应用于 RGB 的滤色器通道
ColorFiltered(
colorFilter: ColorFilter.linearToSrgbGamma(),
child: ImageDescWidget(),
)
- 效果
- ColorFilter.srgbToLinearGamma()
创建一个滤色器,将 sRGB 伽马曲线的反转应用于 RGB 通道
- ColorFilter.matrix
构造一个通过5x5矩阵变换颜色的滤色器
// 通过矩阵转换为颜色过滤器
const ColorFilter sepia = ColorFilter.matrix(<double>[
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0, 0, 0, 1, 0,
]);
ColorFiltered(
colorFilter: sepia,
child: ImageDescWidget(),
)
- 效果
提问一下
如果现在 PM 要求你在特殊节日,统一给 App 设置为灰色你会怎么做呢?
实现代码
// 套在 App 的最外层
ColorFiltered(
colorFilter: ColorFilter.mode(
// 设置混合颜色和模式
Colors.grey,
BlendMode.saturation,
),
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Widgets'),
),
)
运行效果
ImageFiltered(图片过滤器)
不要被这个名字所迷惑,上面我们也看到了,Image
的着色器是通过 ColorFilter
来处理的,在 Flutter 中万物皆 Widget ,所以这里的 ImageFiltered
并不是说作用于图片的,只是有些通常我们应用的图片的过滤器在这里实现了。
ImageFilter.blur(模糊过滤器)
在 Flutter
中是如何给 Widget
添加模糊效果呢?就是使用这个,下面我们来看看怎么使用吧
- 代码实现
ImageFiltered(
// 设置模糊过滤器
imageFilter: ImageFilter.blur(
sigmaX: 4,
sigmaY: 4,
// tileMode: TileMode.clamp,
// tileMode: TileMode.decal,
// tileMode: TileMode.mirror,
// tileMode: TileMode.repeated,
),
child: ImageWidget(),
)
- 预览效果
| 原图 | 模糊度 4 | 模糊度 6 |
| --- | --- | --- |
|
|
|
|
这里可以看出随着模糊度的增加,Widget 大小也随着向外扩展响应的半径距离,填充方式似乎大体看这不是等比缩放拉伸
- tileMode - 平铺方式
| TileMode.clamp(默认) | TileMode.decal |
| :---: | :---: |
|
|
| |
超出区域取边缘最接近的颜色平铺 | 超出区域梯度透明 | | TileMode.mirror | TileMode.repeated | |
|
| |
超过区域与区域内呈来回镜像 |
超过区域重复平铺 |
ImageFilter.matrix(矩阵过滤器)
这里可以通过矩阵的转换来实现,平移、缩放、旋转、倾斜的一些列操作
- 代码实现
ImageFiltered(
// 缩放
imageFilter: ImageFilter.matrix(Matrix4.diagonal3Values(2, 2, 0).storage),
// 倾斜
// imageFilter: ImageFilter.matrix(Matrix4.skewY(pi / 8).storage),
child: ImageWidget(),
// Widget 效果
// child: ImageDescWidget(),
)
-
效果 | 缩放 | 倾斜 | | :---: | :---: | |
|
|
-
Widget 效果 | 缩放 | 倾斜 | | :---: | :---: | |
|
|
ImageFilter.compose(组合过滤器)
上面我们聊的是单一的过滤器效果,很多情况下我们需要组合使用,这时就可以用到这个啦,我们直接看效果
- 上代码
ImageFiltered(
imageFilter: ImageFilter.compose(
// 模糊
outer: ImageFilter.blur(
sigmaX: 4,
sigmaY: 4,
),
// 倾斜
inner: ImageFilter.matrix(Matrix4.skewY(pi / 8).storage),
),
child: ImageDescWidget(),
)
- 看效果
BackdropFilter(背景过滤器)
上面的内容都是对整个 Widget 进行添加过滤器,很多时候我们,如果我们要实现背景滤镜的效果,就需要添加 Stack 来实现了
看源码
可以看到源码非常简单,其中过滤器直接是 ImageFilter 过滤器,所以上面聊过的过滤器都可以使用。
上代码
Stack(
alignment: Alignment.bottomCenter,
children: [
// 背景
ImageWidget(),
// 添加剪裁
ClipRect(
child: BackdropFilter(
// 模糊过滤器
filter: ImageFilter.blur(
sigmaX: 4,
sigmaY: 4,
),
// 设置子项
child: Container(
color: Colors.white.withOpacity(0.4),
alignment: Alignment.center,
padding: const EdgeInsets.all(6),
child: Text(
'🌸 樱花 🌸',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
)
看效果
- 如果我们不添加剪裁
- 如果改成
ImageFiltered
Stack(
alignment: Alignment.bottomCenter,
children: [
// 背景
ImageWidget(),
// 添加剪裁
ImageFiltered(
// 模糊过滤器
imageFilter: ImageFilter.blur(
sigmaX: 0.5,
sigmaY: 0.5,
),
// 设置子项
child: Container(
color: Colors.white.withOpacity(0.4),
alignment: Alignment.center,
padding: const EdgeInsets.all(6),
child: Text(
'🌸 樱花 🌸',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
],
)
- 效果如下
BackdropFilter 和 ImageFiltered 的区别
对比项 | BackdropFilter | ImageFiltered |
---|---|---|
作用对象 | 背景内容 | 子项整体 |
作用范围 | 整体背景,缩小需要加剪裁 | 子项大小 |
源码仓库
基于 Flutter 🔥 最新版本
参考链接
- ColorFiltered (Flutter Widget of the Week)
- Flutter-ColorFiltered
- ImageFiltered (Flutter Widget of the Week)
- Flutter-ImageFiltered
- BackdropFilter (Flutter Widget of the Week)
- Flutter-BackdropFilter
关注专栏
- 此文章已收录到下面👇 的专栏,可以直接关注
- 更多文章继续阅读|系列文章持续更新
👏 欢迎点赞➕收藏➕关注,有任何问题随时在下面👇评论,我会第一时间回复哦
转载自:https://juejin.cn/post/6978867764186316808