23
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

flutter_hooks を使って StatelessWidget で AnimationController を使う

Last updated at Posted at 2020-12-07

はじめに

この記事は Flutter #1 Advent Calendar 2020 の 8 日目の記事です。 Flutter 歴半年の新人ですが、よろしくお願いします。

今回は、「 flutter_hooks を使って StatelessWidget で AnimationController を使う」という題で書きます。題で全て言ってしまってる感が強いですが、私と同じように StatelessWidget でも AnimationController を使ってアニメーションを実装したい、という方の助けになれれば幸いです。

実装する画面

以下のような画面を実装します。実装をシンプルにするためにあえてアニメーションも簡単なものにしています。
ezgif.com-gif-maker.gif

StatefulWidget での実装

Flutter ではアニメーションを行う際に、しばしば AnimationController を使います。以下に、 AnimationController を使うサンプルを示します。

SampleScreen.dart
class SampleScreen extends StatefulWidget {
  @override
  _SampleScreenState createState() => _SampleScreenState();
}

class _SampleScreenState extends State<SampleScreen>
    with SingleTickerProviderStateMixin {
  Animation<double> tweenAnimation;
  AnimationController animationController;

  initState() {
    super.initState();

    animationController = AnimationController(
        duration: const Duration(milliseconds: 250), vsync: this);

    tweenAnimation = Tween(begin: 0.0, end: 1.0).animate(animationController)
      ..addListener(() {
        setState(() {});
      });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sample'),
      ),
      body: Stack(
        children: [
          Positioned(
            left: tweenAnimation.value * 275.0,
            top: tweenAnimation.value * 400.0,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.yellow,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          if (animationController.isCompleted) {
            animationController.reverse();
          } else {
            animationController.forward();
          }
        },
      ),
    );
  }
}

上のコードのように、 AnimationController を初期化する際は vsync に TickerProvider 型で createTicker メソッドを持つものを入れる必要があります。 この条件を満たすために手っ取り早く行われることが多いのが、 State に with SingleTickerProviderStateMixin や TickerProviderStateMixin を付け加えることです。ですが、 State を使う以上、 Widget は StatefulWidget にすることになります。 私は極力すべての画面を StatelessWidget で実装しようと考えていたため、このアニメーションのためだけに StatefulWidget に変更するのは抵抗がありました。

使用するパッケージ

以下のパッケージを使います。
flutter_hooks

StatelessWidget での実装

同じようなアニメーションを、 flutter_hooks を使って StatelessWidget を使って実装した例を示します。

SampleScreen.dart
class SampleScreen extends HookWidget {
  @override
  Widget build(BuildContext context) {
    
    final animationController = useAnimationController(
      duration: const Duration(milliseconds: 250),
    );
    final tweenAnimation =
        Tween(begin: 0.0, end: 1.0).animate(animationController);

    return Scaffold(
      appBar: AppBar(
        title: Text('Sample'),
      ),
      body: Stack(
        children: [
          AnimatedBuilder(
            animation: animationController,
            builder: (BuildContext context, Widget child) {
              return Positioned(
                left: tweenAnimation.value * 275.0,
                top: tweenAnimation.value * 400.0,
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.yellow,
                ),
              );
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          if (animationController.isCompleted) {
            animationController.reverse();
          } else {
            animationController.forward();
          }
        },
      ),
    );
  }
}

flutter_hooks の機能を使う時は、StatelessWidget を継承した、「HookWidget」を継承します。継承すると、buildメソッド内でいくつかの useXXX というメソッドを使うことができるようになります。今回使用する useAnimationController は、 vsync を使うことなく AnimationController を取得することができます。あとは、取得した AnimationController を AnimatedBuilder の controller に入れて、 builder でアニメーションする Widget を組み立てれば完成です。

おわりに

flutter_hooks をいうパッケージを使うことで StatelessWidget でも AnimationController を使うことができる、ということを書きました。 flutter_hooks は他にも Future がより簡単に書けたり TextEditingController や ScrollController も取得できたりいろいろできるパッケージですが、私が一番悩んでいて解決できて感動した機能がこれでした。私と同じように、アニメーションの実装のために StatefulWidget を使いたくない、という方の助けになっていましたら幸いです。
以上で、 8 日目の記事は終了します。ありがとうございました!!

23
11
1

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
23
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?