1. 背景

最近一个需求改版UI视觉觉得微信朋友圈的边际高斯含糊挺好看,然后就苦逼吭哧的测验在Flutter完成了,来看微信朋友圈点击展开的大图作用图:

Flutter实现微信朋友圈高斯模糊效果

微信朋友圈高斯含糊作用大约分4部分区域完成,如下图:

Flutter实现微信朋友圈高斯模糊效果

居中图片为原始图,然后背景含糊全图是原始图扩大cover形式的高斯含糊,在上下两个区域分别是两层单独处理鸿沟的高斯含糊作用特别处理,因而有时分能够看到微信朋友圈在上下两边有明显分界线;

2. 实践

在Flutter侧完成高斯含糊比较简略,能够直接运用体系的BackdropFilter函数完成,需求传入一个filter方法,然后对child区域进行含糊过滤;

  const BackdropFilter({
    Key? key,
    required this.filter,
    Widget? child,
    this.blendMode = BlendMode.srcOver,
  }) : assert(filter != null),
       super(key: key, child: child);     

Flutter提供了简化ImageFiltered完成高斯含糊,代码如下:

ImageFiltered(
    imageFilter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
    child: Image.network(url,fit: BoxFit.cover, height: expandedHeight, width: width),
),

通过此方法,能够十分简约完成全屏高斯含糊~,现在难点是上下鸿沟区域的鸿沟含糊处理,这儿需求运用一个ShaderMask组件,在Flutter侧ShaderMask主要是完成突变过渡才能的;

  const ShaderMask({
   Key? key,
   required this.shaderCallback,
   this.blendMode = BlendMode.modulate,
   Widget? child,
 }) : assert(shaderCallback != null),
      assert(blendMode != null),
      super(key: key, child: child);

其需求shaderCallback回调突变Shader,共提供3种突变形式:

  • RadialGradient:放射状突变
  • LinearGradient:线性突变
  • SweepGradient:扇形突变

这儿咱们需求运用线性突变LinearGradient从上到下的突变过渡,代码如下:

             ShaderMask(
              shaderCallback: (Rect bounds) {
                return const LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Colors.transparent,
                    Colors.white,
                    Colors.transparent
                  ],
                ).createShader(bounds);
              },
              child: Image.network(url,
                  fit: BoxFit.cover, height: closeHeight, width: width),
            )

就这样完成了?当我运行时分呈现如下作用,作用还挺好的:

Flutter实现微信朋友圈高斯模糊效果

可是当我把封面图url替换了一个淡色图片,却呈现如下作用,中间区域变成了黑色的,看来是我想的简略了:

Flutter实现微信朋友圈高斯模糊效果

剖析了下Flutter线性过度源码,其将色彩进行过渡, Color transparent = Color(0x00000000) , 而 Color white = Color(0xFFFFFFFF),能够看到除了透明度之外,需求确保色彩不要产生大改变,其实咱们诉求仅仅需求将透明度产生突变即可,因而将Colors.white改为Colors.black,

             ShaderMask(
              shaderCallback: (Rect bounds) {
                return const LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Colors.transparent,
                    Colors.black,
                    Colors.transparent
                  ],
                ).createShader(bounds);
              },
              child: Image.network(url,
                  fit: BoxFit.cover, height: closeHeight, width: width),
            )

呈现如下作用:

Flutter实现微信朋友圈高斯模糊效果

这儿色彩形似契合预期,可是混合形式呈现了问题,学过Android开发的一定特点如下这张BlendMode混合形式图片:

Flutter实现微信朋友圈高斯模糊效果

ShaderMaster默认的混合形式是BlendMode.modulate,这个我也解说不清楚:这儿有一篇相关文章/post/684490…

这儿咱们将混合形式替换为BlendMode.dstIn:只显示src和dst重合部分,且src的重合部分只要不透明度有用,通过这些操作后,整体作用最终如下所示:

Flutter实现微信朋友圈高斯模糊效果

最终奉上完好demo的相关代码:

  Widget buildCover(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    double expandedHeight = 600;
    double closeHeight = 300;
    const String url =
        'https://www.6hu.cc/files/2022/12/1670961338-0421f1cf6f58e9e.png';
    return Container(
      height: expandedHeight,
      alignment: Alignment.center,
      child: Stack(
        children: [
          ImageFiltered(
            imageFilter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
            child: Image.network(url,
                fit: BoxFit.cover, height: expandedHeight, width: width),
          ),
          Container(
            height: expandedHeight,
            alignment: Alignment.center,
            child: ShaderMask(
              shaderCallback: (Rect bounds) {
                return const LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Colors.transparent,
                    Colors.black,
                    Colors.transparent
                  ],
                ).createShader(bounds);
              },
              blendMode: BlendMode.dstIn,
              child: Image.network(url,
                  fit: BoxFit.cover, height: closeHeight, width: width),
            ),
          )
        ],
      ),
    );
  }

3. 总结

通过实践,发现Flutter完成高斯含糊BackdropFilter/ImageFiltered组件,突变完成方法ShaderMask,此外还需求把握图形学的BlendMode混合形式,以后在碰到相似需求时分主张直接砍了UI视觉吧~~费力~~~~