0
点赞
收藏
分享

微信扫一扫

【译】用户与Flutter交互时的粒子动画


依旧是 ​​simple_animations​​ 的漂亮动画应用。

​​simple_animations​​ 已经完成对 Flutter Web 的支持,并且其​​背景动画效果(文章)​​ 的演示例子成为了 Flutter Web 的官方示例。

在继​​《带有Flutter的粒子动画》​​ 之后,今天这一篇将介绍如何使用粒子动画与用户交互的。

【译】用户与Flutter交互时的粒子动画_flutter

如上图所示,动画是一种“廉价”的点击效果,“地鼠”在 6 个不同的地方短暂出现,当单击一个地鼠(“圆”)时,它将分裂成多个颗粒,然后经过一段随机的时间后,它们再次出现,类似一个简单的反应游戏(打地鼠)。

【译】用户与Flutter交互时的粒子动画_flutter_02

地鼠控件

如下代码所示是一个简化的地鼠控件代码:

class Mole extends StatefulWidget {
@override
_MoleState createState() => _MoleState();
}

class _MoleState extends State<Mole> {
final List<MoleParticle> particles = [];

bool _moleIsVisible = false;

@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
child: _buildMole(),
);
}

Rendering _buildMole() {
return Rendering(
onTick: (time) => _manageParticleLifecycle(time),
builder: (context, time) {
return Stack(
overflow: Overflow.visible,
children: [
if (_moleIsVisible)
GestureDetector(onTap: () => _hitMole(time), child: _mole()),
...particles.map((it) => it.buildWidget(time))
],
);
},
);
}

Widget _mole() {
return Container(
decoration: BoxDecoration(
color: Colors.brown, borderRadius: BorderRadius.circular(50)),
);
}

_hitMole(Duration time) {
_setMoleVisible(false);
Iterable.generate(50).forEach((i) => particles.add(MoleParticle(time)));
}

_manageParticleLifecycle(Duration time) {
particles.removeWhere((particle) {
return particle.progress.progress(time) == 1;
});
}

}

对于“地鼠”,我们使用 ​​GestureDetector​​​ 替换 ​​Container​​​ 来将用户的点击放到 ​​_hitMole​​​ 方法中,这些“地鼠”与颗粒通过 ​​Stack​​ 堆叠到一起。

在该 ​​_hitMole()​​​ 方法的内部,我们隐藏了“地鼠”容器,并生成了 50 个 ​​MoleParticle​​​ 粒子,该类还提供了 ​​buildWidget()​​ 用于构建小“地鼠”粒子。

最后通过 ​​Rendering​​​ 控件实现绘制,它采用一个 ​​onTick​​​ 可以让我们更方便的处理粒子的生命周期,在我们的 ​​_manageParticleLifecycle()​​ 方法中,我们在动画完成后删除了所有粒子。

粒子动画

我们的粒子动画一开始覆盖在原始的“地鼠”容器上,然后随着时间的流逝,粒子容器随机向四周方向飞行直到粒子的容器大小缩减为 0。

【译】用户与Flutter交互时的粒子动画_前端_03

如下代码所示, ​​MoleParticle​​ 类实现了这个行为效果:

class MoleParticle {
Animatable tween;
AnimationProgress progress;

MoleParticle(Duration time) {
final random = Random();
final x = (100 + 200) * random.nextDouble() * (random.nextBool() ? 1 : -1);
final y = (100 + 200) * random.nextDouble() * (random.nextBool() ? 1 : -1);

tween = MultiTrackTween([
Track("x").add(Duration(seconds: 1), Tween(begin: 0.0, end: x)),
Track("y").add(Duration(seconds: 1), Tween(begin: 0.0, end: y)),
Track("scale").add(Duration(seconds: 1), Tween(begin: 1.0, end: 0.0))
]);
progress = AnimationProgress(
startTime: time, duration: Duration(milliseconds: 600));
}

buildWidget(Duration time) {
final animation = tween.transform(progress.progress(time));
return Positioned(
left: animation["x"],
top: animation["y"],
child: Transform.scale(
scale: animation["scale"],
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.brown, borderRadius: BorderRadius.circular(50)),
),
),
);
}
}

在创建粒子时,我们通过计算出随机目标位置,并将这些信息存储到补间动画里。这里使用了 ​​simple_animations​​ 的 ​​MultiTrackTween​​ ,因为可以实现一次添加 3 个不同的补间动画属性。

然后这里创建一个 ​​AnimationProgress​​ 用来跟踪动画的进度,我们这里只需要向他提供当前时间即可。

最后通过 ​​buildWidget()​​​ 将动画补间值和进度结合 ​​Transform.scale​​​ 和 ​​Positioned​​ 来达到移动和缩放的效果。

【译】用户与Flutter交互时的粒子动画_前端_04

这里排除了一些重生相关的逻辑,但是您可以在 ​​Simple Animations Example App​​ 中找到完整的演示代码。

这是应用到 ​​CarGuo/gsy_github_app_flutter​​ 项目启动页的效果:

【译】用户与Flutter交互时的粒子动画_前端_05

资源推荐

  • Github :​​github.com/CarGuo​​
  • 开源 Flutter 完整项目:​​github.com/CarGuo/GSYG…​​
  • 开源 Flutter 多案例学习型项目: ​​github.com/CarGuo/GSYF…​​
  • 开源 Fluttre 实战电子书项目:​​github.com/CarGuo/GSYF…​​
  • 开源 React Native 项目:​​github.com/CarGuo/GSYG…​​

【译】用户与Flutter交互时的粒子动画_前端_06

举报

相关推荐

0 条评论