【Flutter 组件集录】FadeInImage| 8月更文挑战

前言:

这是我参与8月更文挑战的第 10 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战,我准备在本月挑选 31 个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录 的重要素材。希望可以坚持下去,你的支持将是我最大的动力~

本系列 组件文章 列表
1.NotificationListener 2.Dismissible 3.Switch
4.Scrollbar 5.ClipPath 6.CupertinoActivityIndicator
7.Opacity 8.FadeTransition 9. AnimatedOpacity
10. FadeInImage[本文]

一、认识 FadeInImage 组件

我们都知道,图片无论是从资源、文件、网络加载,都不会立刻完成,这样会出现短暂的空白,尤其是网络图片。自己处理默认占位图也比较麻烦。FadeInImage 的作用就是:在目标图片加载完成前使用默认图片占位,加载完成后,目标图片会渐变淡入,默认图片会渐变淡出,这样可以既解决图片加载占位问题,渐变的动画在视觉上也不显突兀。本文,就来全面介绍一下 FadeInImage 组件的使用以及简单的源码实现。


1. FadeInImage 基本信息

首先,它是一个 StatelessWidget,就说明它本身不会维护复杂的状态类,只是在 build 方法中负责组件的构建。

在普通构造中,必须传入两个 ImageProvider 对象,image 表示待加载的目标图片资源,placeholder 表示目标图片加载过程中显示的占位图片资源。另外还有很多用于配置图片和动画的属性,后面再一一介绍。

final ImageProvider placeholder;
final ImageProvider image;
复制代码

2.FadeInImage 的简单使用

只有知道两个图片资源就能最简单地使用 FadeInImage,另外可以通过 widthheight 限制图片的大小。下面头像是使用网络图片,黑色的是占位图,效果如下:

属性名 类型 默认值 用途
placeholder ImageProvider required 占位图片资源
image ImageProvider required 目标图片资源
width double null 图片宽
height double null 图片高
class FadeInImageDemo extends StatelessWidget{
  final headUrl =
      'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/5b2b7b85d1c818fa71d9e2e8ba944a44~300x300.image';
  @override
  Widget build(BuildContext context) {
    return FadeInImage(
      width: 100,
      height: 100,
      placeholder: AssetImage(
        'assets/images/default_icon.png',
      ),
      image: NetworkImage(headUrl),
    );
  }
}
复制代码

3.FadeInImage 动画配置

淡出动画 fadeOut 是针对占位图 而言的,淡入动画 fadeIn 是针对目标图 而言的,我们可以配置两个动画的时长和曲线来达到期望的动画效果,如下是测试案例的效果:

属性名 类型 默认值 用途
fadeOutDuration Duration 300 ms 占位图淡出时长
fadeOutCurve Curves Curves.easeOut 占位图淡出动画曲线
fadeInDuration Duration 700 ms 目标图淡入时长
fadeInCurve Curves Curves.easeIn 目标图淡入动画曲线
FadeInImage(
  width: 100,
  height: 100,
  fadeOutDuration:Duration(seconds: 1),
  fadeOutCurve: Curves.easeOutQuad,
  fadeInDuration: Duration(seconds: 2),
  fadeInCurve: Curves.easeInQuad,
  placeholder: AssetImage(
    'assets/images/default_icon.png',
  ),
  image: NetworkImage(headUrl),
);
复制代码

4.FadeInImage 的图片错误构建器

既然是图片加载,就可能出错,这两个 XXXErrorBuilder 就是用来处理当图片加载错误时应该如何显示。如果不处理,就会像下面这样:

我们可以指定 XXXErrorBuilder 回调来构建错误时显示的组件,如下当占位符错误,显示蓝色 Container 示意一下,你可以指定任意的 Widget

属性名 类型 默认值 用途
placeholderErrorBuilder ImageErrorWidgetBuilder null 占位图加载错误时构建器
imageErrorBuilder ImageErrorWidgetBuilder null 目标图加载错误时构建器
class FadeInImageDemo extends StatelessWidget{

  final headUrl =
      'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/5b2b7b85d1c818fa71d9e2e8ba944a44~300x300.image';

  @override
  Widget build(BuildContext context) {
    return
    FadeInImage(
      width: 100,
      height: 100,
      fadeOutDuration:Duration(seconds: 1),
      fadeOutCurve: Curves.easeOutQuad,
      fadeInDuration: Duration(seconds: 2),
      fadeInCurve: Curves.easeInQuad,
      placeholderErrorBuilder: _placeholderErrorBuilder,
      placeholder: AssetImage(
        'assets/images/default_icon2.png',
      ),
      image: NetworkImage(headUrl),
    );
  }

  Widget _placeholderErrorBuilder(BuildContext context, Object error, StackTrace? stackTrace) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.blue,
    );
  }
}
复制代码

5.FadeInImage 其他属性

剩下的几个属性都是传给 Image 的,也就是说作用和 Image 中的属性一致,这里就不展开了。


6.FadeInImage 的其他构造

除了普通构造之外,FadeInImage 还有 assetNetworkmemoryNetwork ,这两者只是占位组件是 asset 路径 还是 Uint8List 字节数组的区别。这两个构造的目的是便于使用,可以指定缩放以及宽高。


可以看到两个 ImageProvider 成员对象会通过 ResizeImage 进行处理,通过 ResizeImage 可以更改图片资源的大小,通常用于减少 ImageCache 的内存占用。

到这里,FadeInImage 的使用方面就介绍完了。下面来看一下,作为一个 StatelessWidget , FadeInImage 为什么可以执行这么复杂的组件内容变化。


二、 FadeInImage 组件的源码实现

1. FadeInImage 组件的构建

对于 StatelessWidget 而言,逻辑基本上只在 build 方法中如何构建组件。如下是 FadeInImage#build,会通过 _image 方法创建 result 组件,并且一个 frameBuilder 的构建回调,使用了 _AnimatedFadeOutFadeIn 组件。


如果 excludeFromSemantics=false 会套上一个语义组件,Semantics 。这就是 FadeInImage 构造的全部内容。


_image 方法就是根据入参和成员属性构建 Image 组件而已,也没什么特别的。现在核心就是 frameBuilder 的回调会构建 _AnimatedFadeOutFadeIn 。那 Image#frameBuilder 是什么时候会调用呢?先让子弹飞一会,现在看一下 _AnimatedFadeOutFadeIn 的实现。


2. _AnimatedFadeOutFadeIn 组件的实现

它继承自 ImplicitlyAnimatedWidget ,表示其是一个 隐式动画组件,在 AnimatedOpacity 一文中介绍过隐式组件的特性:外界只需要改变相关配置属性,进重构组件就能触发动画,无需操作动画控制器。

_AnimatedFadeOutFadeInState#build 中可以看出,淡入淡出的动画实现是通过两个 FadeTransition完成的,两者通过 Stack 叠合。这样看来是不是豁然开朗。


3. 渐变动画如何触发

AnimatedOpacity 一文中也说过,对于隐式组件,动画的启动是通过改变属性和重建组件,来触发 State#didUpdateWidget ,开启动画。

那问题来了,作为 StatelessWidgetFadeInImage ,如何重构 _AnimatedFadeOutFadeIn 。现在再来看 frameBuilder 就正是时候。Image 组件的 frameBuilder 是一个回调的构建,它会在 _ImageState 构建时触发。


第一次是图片没有加载:

第二次是图片加载完成:

属性变化 + 组件重构,从而触发隐式组件的动画启动,完成需求。可以看出 FadeInImage 是非常巧妙的。FadeInImage 的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~

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