引言
我最近在做仿微信朋友圈的页面,其中有个功能就是预览图点击后查看大图。在实现细节的过程中,我发现Flutter的Hero动画在只传入tag&child的情况下,大图的 contain 在切换预览图的 cover 过程中会“闪一下",很不丝滑,cover 切换 contain 过渡也不完美。如下图:
于是我上网搜索了关于Fit改变情况下的Hero动画解决方案,并没有搜索到相关内容,于是就有了这篇文章。
实现方法
flightShuttleBuilder
为了控制Hero动画飞行时的动画,我们需要用到flightShuttleBuilder
官方文档传送门
flightShuttleBuilder是Hero的一个参数,用于控制Hero动画飞行时的组件。可以拿到以下内容
核心代码
缩略图Hero内
flightShuttleBuilder: (
BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,
) {
return LayoutBuilder(builder: (context, heroCovariant) {
// 先让限制图片的Sizedbox尺寸铺满Hero
double height = heroCovariant.maxHeight;
double width = heroCovariant.maxWidth;
// 提前获取好的图片的长宽比
double imageRatio = imageWidth / imageHeight;
// 手搓类似contain的逻辑,计算出大图的contain下的实际宽高
if (width / height > imageRatio) {
// 使用Hero的height 并让width跟随宽高比(fit height)
width = height * imageRatio;
} else {
// 反之使用Hero的width 并让height跟随宽高比(fit width)
height = width * (1 / imageRatio);
}
return Center( // 防止 SizedBox 铺满Hero
child: SizedBox(
// 使用 flightShuttleBuilder 提供的 animation.value 获取Hero动画进度
// 在缩略图宽高的基础上,根据动画进度慢慢增加Hero的宽高,直到大图的contain实际宽高(上方已经计算出)
width: thumbnailCovariant.maxWidth +
(width - thumbnailCovariant.maxWidth) * animation.value,
height: thumbnailCovariant.maxHeight +
(height - thumbnailCovariant.maxHeight) * animation.value,
child: FittedBox(
fit: BoxFit.cover,
clipBehavior: Clip.antiAlias,
child: toHeroContext.widget)),
);
});
},
实现后效果
效果也是非常的丝滑~