Flutter Lottie 动画库之「图片模糊」踩坑记录


theme: smartblue

首发于语雀平台 排版格式更好,阅读体验+1

背景

接到一个需求,设计稿是长这样的:<br /><br />实现后的效果是这样的:<br />

所以问题在哪里?

用设计的眼睛来看的话,可以发现:两个小人物的表情非常模糊,有明显的毛边/毛刺。<br />引用设计一姐的话来说就是这样:

两个氛围组按钮素材清晰度低,有明显毛边

这里看到的只是静态内容,实际上两个人物头像都是可点击的,会有相应的动画出现。<br />

<br />如 GIF 图所示,点击头像按钮会出现一个缩放的动画,与之伴随的还有一个头像飞天的一个动画。<br />至于动画的实现,正如标题所诉,这里的动画实现都是使用的「Lottie」动画库。

设计给了我一个「json」文件和一个「image」文件,我才发现原来这根本不是一个矢量动画,只是利用 Lottie 能力针对图片做的一个简单的缩放动画。

但是使用 Lottie 目前的问题是:Lottie 动画的图片会变得很模糊同时伴有毛边出现。
<br />
所以,我们需要解决图片毛边的一个问题,也就是搞清楚为何会出现这个问题。

<a name="rNpLV"></a>

问题排查

首先,不是图片质量的问题,图片给的是x3的质量图,使用 Image 显示完全没有问题。

所以,问题明显出现在「Lottie」这个库身上,但是排查这个「Lottie」显然会花费很多时间,于是乎就有了下面的对话:<br />

解决不了设计一姐,看来只能去研究一下「Lottie」背后的图片机制问题了,生活不易,默默叹气。

Lottie 排查

经过我的一番操作后,发现问题很可能出现在这里:

src/model/layer/image_layer.dart#L37

class ImageLayer extends BaseLayer {
  final Paint paint = Paint();
  BaseKeyframeAnimation<ColorFilter, ColorFilter?>? _colorFilterAnimation;

  ImageLayer(LottieDrawable lottieDrawable, Layer layerModel)
    : super(lottieDrawable, layerModel);

  @override
  void drawLayer(Canvas canvas, Size size, Matrix4 parentMatrix,
                 {required int parentAlpha}) {
    var bitmap = getBitmap();
    if (bitmap == null) {
      return;
    }
    var density = window.devicePixelRatio;

    paint.setAlpha(parentAlpha);
    if (_colorFilterAnimation != null) {
      paint.colorFilter = _colorFilterAnimation!.value;
    }
    canvas.save();
    canvas.transform(parentMatrix.storage);
    var src =
      Rect.fromLTWH(0, 0, bitmap.width.toDouble(), bitmap.height.toDouble());
    var dst = Rect.fromLTWH(
      0, 0, bitmap.width * density, bitmap.height.toDouble() * density);
    canvas.drawImageRect(bitmap, src, dst, paint);
    canvas.restore();
  }

  Image? getBitmap() {
    var refId = layerModel.refId;
    return lottieDrawable.getImageAsset(refId);
  }

  ...
}

其中,ImageLayer#drawLayer 这个方法的实现很可能有问题,因为找来找去只发现这个地方会处理图片绘制相关的逻辑 ?。

上述代码的逻辑就是:将位图信息取出来,计算位置、处理缩放,最后绘制到 canvas 上,这样就完成了一个图层的叠加了。

那么问题出在哪里呢? 说实话我并不知道,我在这里卡了比较久,不太理解为何绘制出来的图片质量很低(看来是我的基础没打好,遇到问题干瞪眼了)。

所以我决定,还是发动看家本领吧。<br />
于是,我在搜索栏中输入了 image quality,然后发起了一次搜索请求,最后我得到了如下结果:

我看到了一个 PR,打着红色的 ❌,还没有 Merge,我点进去一探究竟。

尼玛,这不就是我想要的东西吗?「filterQuality」,可以改变图片绘制质量的参数啊,这和我一开始猜测的一摸一样,但是我没搞懂要在哪里配置绘图质量。

带着好奇赶紧看一下代码再说:

+ paint.filterQuality = lottieDrawable.filterQuality ?? FilterQuality.none;

原来如此,只需要在「Paint」对象上设置「filterQuality」即可。只是我之前并没有接触过「Paint」,所以对「Paint」提供的参数不太清楚,导致虽然定位大致的问题,也很难准确找到问题所在。

PR Merge

看来已经有人发现这个问题并且提了 PR,只是作者一直没有合并而已。所以,我做的第一件事情就是,催促作者哈哈。

没想到作者非常给力,很快就回复我了,然后就非常迅速的修复了这个 PR 并且发了新版本。这里真的需要给作者点个赞 。

总结 ?

自此,问题总算是得到了一个满意的解决。我也不用再苦逼去手动实现这个动画了。<br />但是对 Flutter 的学习还有很长的路要走,一刻也不能停下来,尤其是绘制等基础部分需要再加加油~

作者:dreamer2q 原文地址:https://juejin.cn/post/7125079375426355230

%s 个评论

要回复文章请先登录注册