背景
在最近的项目中,我遇到了一个需求:当满足特定条件时,需要将图像转换为灰度。例如,用户个人资料页面有一组用来显示个人社交信息,并展示相关社交平台图标,如果用设置了社交信息,则该社交平台的图标应处理点亮状态,如果没有设置,则应处于禁用状态,也就是是说,我需要把对应图标的颜色改为灰度模式。这看起来很简单,特别是对于那些单一颜色的图标,对吧?但实际上,有一些图标是彩色的而且色彩丰富,比如说instagram。
BlendMode
我首先研究了Flutter
中的混合模式(BlendMode),结果发现它们确实效果很好 ------ 但这仅适用于没有透明度的JPEG
或PNG
图像。以下是我用于将彩色透明PNG
图像显示为灰度图像的代码。
dart
ColorFiltered(
colorFilter: enabled ? ColorFilter.mode(
Colors.transparent,
BlendMode.multiply,
) : ColorFilter.mode(
Colors.grey,
BlendMode.saturation,
),
child: Image.asset("assets/roundabout.png",),
)
上面用的图片是一个带有透明的PNG
图片,让我们看看效果:

再放一个没有经过处理的demo用的原图:
很显然,这样的效果很糟糕。混合模式(BlendMode)也会影响图像中的透明部分,并将它们也转换为灰色,但我们需要让这些透明区域也不受影响。
颜色矩阵
经过一番研究,我在Flutter文档的深处发现了这个内容。文档中提到了另一个构造函数,它可以用来定义一个矩阵,从而更精细地控制混合模式的应用方式。
于是,我用ColorFilter.matrix
替换了ColorFilter.mode
构造函数,并传入了这些神奇的数字。
dart
ColorFilter.matrix(<double>[
0.2126,0.7152,0.0722,0,0,
0.2126,0.7152,0.0722,0,0,
0.2126,0.7152,0.0722,0,0,
0,0,0,1,0,
])

没错,这正是我一直在寻找的解决方案。文档中还提到了更多示例。大家可以随意尝试这些示例,并对这些数值进行调整。
** 反色(Inversion)** 效果的颜色矩阵:

dart
const ColorFilter invert = ColorFilter.matrix(<double>[
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0, ]);
** 复古棕褐色(Sepia Tone)** 效果的颜色矩阵
dart
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, ]);
个人感觉这个效果适用于复古风格 UI、老照片效果、特定主题界面。
灰度滤镜(Grayscale Color Filter) 效果矩阵
标准灰度滤镜矩阵(最常用)
dart
const ColorFilter greyscale = ColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0, // 红色通道转换
0.2126, 0.7152, 0.0722, 0, 0, // 绿色通道转换
0.2126, 0.7152, 0.0722, 0, 0, // 蓝色通道转换
0, 0, 0, 1, 0, //透明度保持不变
]);
上面的的灰度算法是一个标准的灰度算法,还两种算法可供参考:
简化版灰度矩阵(平均法)
dart
ColorFilter.matrix([
0.333, 0.333, 0.333, 0, 0, // 红色通道取平均值
0.333, 0.333, 0.333, 0, 0, // 绿色通道取平均值
0.333, 0.333, 0.333, 0, 0, // 蓝色通道取平均值
0, 0, 0, 1, 0, // 透明度保持不变
])
高对比度灰度矩阵
dart
ColorFilter.matrix([
0.299, 0.587, 0.114, 0, 0, // 红色通道(电视标准算法)
0.299, 0.587, 0.114, 0, 0, // 绿色通道
0.299, 0.587, 0.114, 0, 0, // 蓝色通道
0, 0, 0, 1, 0, // 透明度保持不变
])
矩阵原理:
- 人眼对红、绿、蓝三色的敏感度不同,公式
亮度 = 0.2126*R + 0.7152*G + 0.0722*B
可模拟真实灰度效果。 - 矩阵中每行对应一个颜色通道(红、绿、蓝、透明度),每列对应输入颜色的分量(R、G、B、A、偏移量)。
让我们再回头看看BlendMode
相关属性:
关键属性解析
属性 | 说明 |
---|---|
colorFilter |
必需参数,指定颜色滤镜。可通过 ColorFilter.mode 或 ColorFilter.matrix 创建。 |
BlendMode |
混合模式(如 colorBurn 、srcIn 等),影响颜色过滤的最终效果。 |
child |
待处理的子组件(通常为 Image 或 Icon 等可视化组件)。 |
注意事项
-
性能影响:
- 复杂的
ColorFilter.matrix
可能对性能产生轻微影响,建议对静态图像提前处理为灰度图。 - 动态切换时,避免在列表或高频率刷新场景中大量使用。
- 复杂的
-
混合模式选择:
BlendMode.color
可保留亮度,仅修改色相和饱和度,适合部分灰度效果。BlendMode.luminosity
直接提取亮度,是最纯净的灰度转换模式。
最后
通过 ColorFiltered
组件,Flutter 提供了简洁高效的图像灰度处理方案。无论是静态效果还是动态交互,合理选择混合模式或矩阵运算,均可灵活实现所需视觉效果。
也希望大家关注我的微信公众号OpenFlutter
。