【譯】使用者與Flutter互動時的粒子動畫

戀貓de小郭發表於2020-01-22

原文連結:medium.com/@felixblasc…

依舊是 simple_animations 的漂亮動畫應用。

simple_animations 已經完成對 Flutter Web 的支援,並且其背景動畫效果(文章) 的演示例子成為了 Flutter Web 的官方示例。

在繼《帶有Flutter的粒子動畫》 之後,今天這一篇將介紹如何使用粒子動畫與使用者互動的。

【譯】使用者與Flutter互動時的粒子動畫

如上圖所示,動畫是一種“廉價”的點選效果,“地鼠”在 6 個不同的地方短暫出現,當單擊一個地鼠(“圓”)時,它將分裂成多個顆粒,然後經過一段隨機的時間後,它們再次出現,類似一個簡單的反應遊戲(打地鼠)。

【譯】使用者與Flutter互動時的粒子動畫

地鼠控制元件

如下程式碼所示是一個簡化的地鼠控制元件程式碼:

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互動時的粒子動畫

如下程式碼所示, 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_animationsMultiTrackTween ,因為可以實現一次新增 3 個不同的補間動畫屬性。

然後這裡建立一個 AnimationProgress 用來跟蹤動畫的進度,我們這裡只需要向他提供當前時間即可。

最後通過 buildWidget() 將動畫補間值和進度結合 Transform.scalePositioned 來達到移動和縮放的效果。

【譯】使用者與Flutter互動時的粒子動畫

這裡排除了一些重生相關的邏輯,但是您可以在 Simple Animations Example App 中找到完整的演示程式碼。

這是應用到 CarGuo/gsy_github_app_flutter 專案啟動頁的效果:

【譯】使用者與Flutter互動時的粒子動畫

資源推薦

【譯】使用者與Flutter互動時的粒子動畫

相關文章