在写下拉刷新的时候,进入页面显示刷新动画,但是动画开始时图片总是会闪烁,怀疑以下几点原因;
1、刷新控件刷新状态切换导致;
2、动画图片资源过少。
使用的刷新插件为:pull_to_refresh
猜想一验证:
刷新状态RefreshStatus.idle
刷新状态RefreshStatus.idle
刷新状态RefreshStatus.refreshing
刷新状态RefreshStatus.refreshing
刷新状态RefreshStatus.completed
刷新状态RefreshStatus.completed
刷新状态RefreshStatus.idle
刷新状态RefreshStatus.idle
如上为进入页面后自动触发刷新:
刷新状态RefreshStatus.canRefresh
刷新状态RefreshStatus.refreshing
刷新状态RefreshStatus.completed
刷新状态RefreshStatus.completed
刷新状态RefreshStatus.completed
刷新状态RefreshStatus.idle
刷新状态RefreshStatus.idle
如上为手动触发刷新。
可以看到除了idle状态会重复执行外,其他状态执行都是正常的,最终验证和控件没有关系。
并且将动画控件单独拿出来也是会出现闪烁,所以排除了控件的影响。
猜想二验证
添加了多张图片后问题依然存在,这猜想也排除。
随后观察日志发现,有这么一句话被打印出来
ProcessProfilingInfo new_methods=3403 is saved saved_to_disk=1 resolve_classes_delay=8000
突然想到是否是读取本地图片的时候耗时导致下一章图片未加载出来。
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: images.length * 100));
animation = Tween<double>(begin: 0, end: (images.length - 1).toDouble()).animate(animationController);
animationController.forward();
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) animationController.forward(from: 0);
});
animation.addListener(() {
currentIndex = animation.value is double ? animation.value.toInt() : 0;
setState(() {});
});
上面即为帧动画,其中images为String类型的List,里面都是本地图片的路径。
@override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 100,
child: Image.asset(
images[currentIndex],
width: 30,
fit: BoxFit.fitWidth,
),
),
);
}
上面为最终的图片显示。
可以看得出来,动画的执行是非常快速的,其速度超过了加载图片的速度,最后导致了,需要加载下一张图片的时候,图片还没有加载,这时候会显示空白,但时间又非常短,所以看起来像在闪烁。
最终考虑通过与预加载图片的方式去处理(大家可以去搜一下怎么预加载本地图片),
但是发现一个更简单的方法,其实Image.asset()有一个类型为bool的属性叫gaplessPlayback,其默认值为false,官方给出的解释是
/// Whether to continue showing the old image (true), or briefly show nothing
/// (false), when the image provider changes. The default value is false.
///
/// ## Design discussion
///
/// ### Why is the default value of [gaplessPlayback] false?
///
/// Having the default value of [gaplessPlayback] be false helps prevent
/// situations where stale or misleading information might be presented.
/// Consider the following case:
///
/// We have constructed a 'Person' widget that displays an avatar [Image] of
/// the currently loaded person along with their name. We could request for a
/// new person to be loaded into the widget at any time. Suppose we have a
/// person currently loaded and the widget loads a new person. What happens
/// if the [Image] fails to load?
///
/// * Option A ([gaplessPlayback] = false): The new person's name is coupled
/// with a blank image.
///
/// * Option B ([gaplessPlayback] = true): The widget displays the avatar of
/// the previous person and the name of the newly loaded person.
///
/// This is why the default value is false. Most of the time, when you change
/// the image provider you're not just changing the image, you're removing the
/// old widget and adding a new one and not expecting them to have any
/// relationship. With [gaplessPlayback] on you might accidentally break this
/// expectation and re-use the old widget.
我们只看第一段,意思是说,当图片提供者发生变化的时候(true),是需要展示旧图片还是什么都不展示(false), 后面就是说为什么默认为false,大致意思是,有一个Person,我们要加载他的头像和名字,同时我们随时可以加载另一个人的名字和头像,如果头像加载失败的话仍然显示前一个人的头像就会出现误导。(大致是这个意思)
然后将这个属性设置为true以后问题得到解决