LoginSignup
0
0

More than 1 year has passed since last update.

【Flutter】IntervalでシーケンシャルなAnimationを実現する

Last updated at Posted at 2021-11-20

はじめに

この様に拡大とフェードアウトをシーケンシャルに設定したい場合にIntervalを使うと良い感じに書けたので紹介します。

Nov-20-2021 21-54-26.gif

AnimationControllerのwhenCompleteを使う方法

Flutter初心者の私がシーケンシャルなAnimationを設定する方法としてまず辿り着いたのがこの方法です。

まず、拡大用のAnimationControllerとフェードアウト用のAnimationControllerをそれぞれ用意します。
そして、次の様なロジックで動かします。

  1. 拡大用のAnimationを再生
  2. 拡大用のAnimationが完了したら、とフェードアウト用のAnimationを再生
  3. フェードアウト用のAnimationが完了したら、拡大用のAnimationを再生

コード

class _HomeWidgetState extends State<HomeWidget> with TickerProviderStateMixin {
  late AnimationController _fadeAnimCtlr;
  late Animation<double> _fadeAnimation;
  late AnimationController _scaleAnimCtlr;
  late Animation<double> _scaleAnimation;

  @override
  void initState() {
    _fadeAnimCtlr = AnimationController(vsync: this, duration: Duration(milliseconds: 1000));
    _fadeAnimation = Tween<double>(begin: 1.0, end: 0.0).animate(_fadeAnimCtlr)
      ..addListener(() {
        setState(() {});
      });
    _scaleAnimCtlr = AnimationController(vsync: this, duration: Duration(milliseconds: 1000));
    _scaleAnimation = Tween<double>(begin: 1.0, end: 3.0).animate(_scaleAnimCtlr)
      ..addListener(() {
        setState(() {});
      });
    repeatAnimation();
  }

  void repeatAnimation() {
    _scaleAnimCtlr.forward().whenComplete(() {
      _fadeAnimCtlr.forward().whenComplete(() {
        _scaleAnimCtlr.reset();
        _fadeAnimCtlr.reset();
        repeatAnimation();
      });
    });
  }

  @override
  void dispose() {
    _fadeAnimCtlr.dispose();
    _scaleAnimCtlr.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    var screenSize = MediaQuery.of(context).size;
    return Stack(
      children: <Widget>[
        Positioned(
          top: screenSize.height * 0.2,
          left: screenSize.width * 0.5,
          child: ScaleTransition(
            scale: _scaleAnimation,
            child: FadeTransition(
                opacity: _fadeAnimation,
                child: Text("Hello\nWorld",
                    style: TextStyle(
                      fontSize: 20,
                      color: Colors.white,
                    ))),
          ),
        ),
      ],
    );
  }
}

Intervalを使う方法

次にここの情報から学んだIntervalを使った方法です。

拡大フェードアウト用のひとつのAnimationControllerを用意し、Intervalを使ってそれぞれのAnimationが動くタイミングを指定します。
全体として2秒のAnimationの前半を拡大、後半をフェードアウトを動作させるというイメージです。

コード

class _HomeWidgetState extends State<HomeWidget> with SingleTickerProviderStateMixin {
  late AnimationController _fadeScaleAnimCtlr;
  late Animation<double> _fadeAnimation;
  late Animation<double> _scaleAnimation;

  @override
  void initState() {
    _fadeScaleAnimCtlr = AnimationController(vsync: this, duration: Duration(milliseconds: 2000));
    _fadeAnimation = Tween<double>(begin: 1.0, end: 0.0).animate(
      CurvedAnimation(parent: _fadeScaleAnimCtlr, curve: Interval(0.5, 1.0)))
      ..addListener(() {
        setState(() {});
      });
    _scaleAnimation = Tween<double>(begin: 1.0, end: 3.0).animate(
      CurvedAnimation(parent: _fadeScaleAnimCtlr, curve: Interval(0.0, 0.5)))
      ..addListener(() {
        setState(() {});
      });
    _fadeScaleAnimCtlr.repeat();
  }

  @override
  void dispose() {
    _fadeScaleAnimCtlr.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    var screenSize = MediaQuery.of(context).size;
    return Stack(
      children: <Widget>[
        Positioned(
          top: screenSize.height * 0.2,
          left: screenSize.width * 0.5,
          child: ScaleTransition(
            scale: _scaleAnimation,
            child: FadeTransition(
                opacity: _fadeAnimation,
                child: Text("Hello\nWorld",
                    style: TextStyle(
                      fontSize: 20,
                      color: Colors.white,
                    ))),
          ),
        ),
      ],
    );
  }
}

まとめ

前者の方法も後者の方法もメリット、デメリットがあると思います。

メリット デメリット
whenComplete 直感的に分かりやすい Animation毎にContorllerが必要
Tickerが複数必要なのでアプリの動作コストが高い
Interval AnmationContorllerがひとつで済む
Tickerがひとつで済むのでアプリの動作コストが低い
直感的に分かりづらい

恐らく、Animationを設定する対象(Widget)が同じであればIntervalを使った方がすっきりして良いと思いますが、別であればAnimationControllerを分けた方が後々良かったりするのではないかと思っています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0