原文連接:medium.com/@felixblasc…git
依舊是 simple_animations 的漂亮動畫應用。github
simple_animations 已經完成對 Flutter Web 的支持,而且其背景動畫效果(文章) 的演示例子成爲了 Flutter Web 的官方示例。bash
在繼《帶有Flutter的粒子動畫》 以後,今天這一篇將介紹如何使用粒子動畫與用戶交互的。app
如上圖所示,動畫是一種「廉價」的點擊效果,「地鼠」在 6 個不一樣的地方短暫出現,當單擊一個地鼠(「圓」)時,它將分裂成多個顆粒,而後通過一段隨機的時間後,它們再次出現,相似一個簡單的反應遊戲(打地鼠)。dom
以下代碼所示是一個簡化的地鼠控件代碼:ide
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()
方法中,咱們在動畫完成後刪除了全部粒子。ui
咱們的粒子動畫一開始覆蓋在原始的「地鼠」容器上,而後隨着時間的流逝,粒子容器隨機向四周方向飛行直到粒子的容器大小縮減爲 0。spa
、以下代碼所示, 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
來達到移動和縮放的效果。
這裏排除了一些重生相關的邏輯,可是您能夠在 Simple Animations Example App 中找到完整的演示代碼。
這是應用到 CarGuo/gsy_github_app_flutter 項目啓動頁的效果: