时光荏苒, 总有一些景色现在再也看不到. 就像夏触不到冬的雪, 冬捉不到夏的蝉. 除了珍惜现在的点滴, 我们也可以利用技术的手段试着还原重现那段时光~

起源

看过这么一张图, 一瞬间感觉很惊艳. 季节跨度作对比, 很难不去惊叹大自然的鬼斧神工. 由此, 也引申出了今天的主题-《Flutter 时光切换效果》.本次, 我们将通过Flutter作为介质. 通过增加怀旧滤镜的方式, 手动将图片还原到过去.然后可以通过时光调整去同时加载不同时光所属的图片.

实现

简单来说, 我们需要完成一个如图所示的widget. 在左边是现在的景色, 右边是过去的景色. 而控制器呢~ 可以切换时间进度.
image

分割图片

首先, 我们需要将图片分布在新旧的图层上. 这里我们可以通过Align 来实现, Align 是什么组件呢? 可能很多人都认为它只是一个用于控制内部对齐方式的一个组件, 实际上它还提供如widthFactor 、heightFactor 这些参数. 这些参数会根据父组件的约束改变子组件最大的可用空间, 这恰恰可以符合分割线的逻辑, 我们只要知道他们各占据多少空间,就可以正好拼接它们自己的部分还原成一张完整的图.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
widthFactor: 0.5,
alignment: Alignment.centerLeft,
child: Image.asset('xxxx'),
),
// 由于图片会超过,所以这里我们需要切割多余的部分
ClipRect(
clipBehavior: Clip.antiAlias,
child: Align(
widthFactor: 0.5,
alignment: Alignment.centerRight,
child: Image.asset('xxxx'),
),
),
],
),

可能到这里,我们还看不出来. 因为图片未做任何处理.

添加怀旧滤镜

这里我们可以通过添加ColorFiltered 为图片增加一个滤镜, 是不是有内味了.

1
2
3
4
5
6
7
8
9
10
11
12
final List<double> _filter = const [
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0 , 0 , 0 , 1, 0,
];

ColorFiltered(
colorFilter: ColorFilter.matrix(_filter),
child: Image.asset('xxxx'),
),

图片上可以很好的对比出来, 左边是原图, 右图明显有种怀古感.实际上目前很多Flutter层用的置灰方案也是基于ColorFiltered 实现的, 唯一不同的是用的矩阵不同罢了.
image

添加控制器

我们发现通过Align 以及ColorFiltered 确实可以让图片达到我们想要的效果, 那如何控制它的进度呢?
这里我们采用Slider ,通过进度的改变动态的更改上面图片的进度

1
2
3
4
5
6
7
8
9
10
11
Slider(
value: _percent,
max: _max,
onChanged: (value) {
if (mounted) {
setState(() {
_percent = value;
});
}
},
),

202212051757.gif

自动变旧

那么, 如何达成本文首图的效果呢? 这里就更简单了,有兴趣的可以自己Diy. 本文为了简单起见(其实是懒), 直接使用了TweenAnimationBuilder 隐式动画来直接生成动画效果. 实际上可以通过AnimationController , 自己定义动画曲线以及时长、效果.

1
2
3
4
5
6
7
TweenAnimationBuilder(
tween: Tween(begin: 0.0, end: 1.0),
duration: Duration(milliseconds: 2000),
builder: (BuildContext context, double value, Widget? child) {
// 这里返回的即之前的widget, 只不过这里的阀值通过AnimationController控制
},
)

202212051759.gif

源码

github.com/weniner/flutter_demo/

结语

这里是WeninerIo,热爱生活且热爱旅行.如果你对这次的分享感兴趣又或者有什么疑惑, 不妨评论区留言 + 关注.期待下一次更好的相遇.