Flutter 中 ColorFiltered、ImageFiltered、BackdropFilter的使用详解 | Flutter Widgets

这是我参与更文挑战的第28天,活动详情查看: 更文挑战

前言

之前我们聊过 Image ,聊过给图片设置颜色,以及各种混合算法的使用,今天我们聊聊 Flutter 中各种过滤器的使用详解。

ColorFiltered(颜色过滤器)

看名字就知道是增加颜色滤镜效果的,下面先回忆一下我们之前聊的 Image 中设置颜色。

  • 一张正常的图片
Image.asset(
  'assets/images/img_03.jpeg',
  width: 375,
  height: 240,
  fit: BoxFit.cover,
)
复制代码

image.png

  • 设置一个颜色
Image.asset(
  'assets/images/img_03.jpeg',
  width: 375,
  height: 240,
  fit: BoxFit.cover,
  color: Colors.pink,
)
复制代码

image.png

  • 设置混合模式
Image.asset(
  'assets/images/img_03.jpeg',
  width: 375,
  height: 240,
  fit: BoxFit.cover,
  color: Colors.pink,
  colorBlendMode: BlendMode.color,
)
复制代码

image.png
最终我们就合成一张这样带滤镜效果

追踪源码

image.png
我我们持续追踪源码到 RenderImage 类中,可以看到最终也是创建了一个 ColorFilter

简单使用

上面只是对 Image 增加滤镜效果,如果我们要对 Widget 增加滤镜效果呢?
这时就需要用到 ColorFiltered 了,下面我们看看怎么使用吧

ColorFiltered(
  // 添加颜色过滤器
  colorFilter: ColorFilter.mode(
    // 设置颜色
    Colors.grey,
    // 设置混合模式
    BlendMode.saturation,
  ),
  child: ImageDescWidget(),
)
复制代码
滤镜前 滤镜后 滤镜后-粉色
image.png image.png image.png

其他构建方法

除了 ColorFilter.mode 我们如果翻看 ColorFilter 的源码,还会发现如下的几种构建方法

  • ColorFilter.linearToSrgbGamma()

构造一个将 sRGB 伽马曲线应用于 RGB 的滤色器通道

ColorFiltered(
  colorFilter: ColorFilter.linearToSrgbGamma(),
  child: ImageDescWidget(),
)
复制代码
  • 效果

image.png

  • ColorFilter.srgbToLinearGamma()

创建一个滤色器,将 sRGB 伽马曲线的反转应用于 RGB 通道

image.png

  • ColorFilter.matrix

构造一个通过5×5矩阵变换颜色的滤色器

// 通过矩阵转换为颜色过滤器
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(),
)
复制代码
  • 效果

image.png

提问一下

如果现在 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'),
  ),
)
复制代码

运行效果

01.gif

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
image.png image.png image.png

这里可以看出随着模糊度的增加,Widget 大小也随着向外扩展响应的半径距离,填充方式似乎大体看这不是等比缩放拉伸

  • tileMode – 平铺方式
TileMode.clamp(默认) TileMode.decal
image.png image.png
image.pngimage.png
超出区域取边缘最接近的颜色平铺
超出区域梯度透明
TileMode.mirror TileMode.repeated
image.png image.png
image.pngimage.png
超过区域与区域内呈来回镜像
image.pngimage.png
超过区域重复平铺

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(),
)
复制代码
  • 效果
缩放 倾斜
image.png image.png
  • Widget 效果
缩放 倾斜
image.png image.png

ImageFilter.compose(组合过滤器)

上面我们聊的是单一的过滤器效果,很多情况下我们需要组合使用,这时就可以用到这个啦,我们直接看效果

  • 上代码
ImageFiltered(
  imageFilter: ImageFilter.compose(
    // 模糊
    outer: ImageFilter.blur(
      sigmaX: 4,
      sigmaY: 4,
    ),
    // 倾斜
    inner: ImageFilter.matrix(Matrix4.skewY(pi / 8).storage),
  ),
  child: ImageDescWidget(),
)
复制代码
  • 看效果

image.png

BackdropFilter(背景过滤器)

上面的内容都是对整个 Widget 进行添加过滤器,很多时候我们,如果我们要实现背景滤镜的效果,就需要添加 Stack 来实现了

看源码

image.png

可以看到源码非常简单,其中过滤器直接是 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,
            ),
          ),
        ),
      ),
    ),
  ],
)
复制代码

看效果

image.png

  • 如果我们不添加剪裁

image.png

  • 如果改成 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,
          ),
        ),
      ),
    ),
  ],
)
复制代码
  • 效果如下

image.png

BackdropFilter 和 ImageFiltered 的区别

对比项 BackdropFilter ImageFiltered
作用对象 背景内容 子项整体
作用范围 整体背景,缩小需要加剪裁 子项大小

源码仓库

基于 Flutter ? 最新版本

参考链接

关注专栏

  • 此文章已收录到下面? 的专栏,可以直接关注
  • 更多文章继续阅读|系列文章持续更新

? 欢迎点赞➕收藏➕关注,有任何问题随时在下面?评论,我会第一时间回复哦

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享