1
0

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 1 year has passed since last update.

[Flutter] Getxで AnimationControllerを使う方法

Posted at

get.png
上の画像は使っていいんですかね。。すごく壁紙?としていいなと思ったので使わせていただきました。

こんにちわ。いせきです。

色々な状態管理があり、人によって何を使うのかがバラバラですね。

僕は、最近GetXを使用して開発をすることが多いです。

ゲームのアプリを作成している段階で、ボタンにアニメーションをつけたいと思っていましたが、なかなかうまくいきませんでした。調べて、試してを繰り返した結果、実装することができたので、共有しようと思います。

GetXとは、

公式では以下のように説明されています。

GetX is an extra-light and powerful solution for Flutter. It combines high-performance state management, intelligent dependency injection, and route management quickly and practically.

詳しくは以下のサイトを参考にしてください。

開発の流れ

今回は、画面を描画する(Screen)と処理などを記載する(Controller)の2ファイルで作成しました。
基本的な書き方などは、他の方が数百倍わかりやすく記載しているので、省略します。

 - lib
   - component
     - button_item
   - home_screen
     - home_screen.dart
     - home_screen_controller.dart 

こんなアニメーションをしたいと思います。見えづらいかもしれませんが、大きくなったり小さくなったりしています。

① AnimationControllerを使う前に必要な処理

GetXControllerの後にwith GetSingleTickerProviderStateMixinをつけるとgetx内でもAnimationControllerに必要なTickerProviderが使えるようになりました。

class HomeScreenController extends GetxController with GetSingleTickerProviderStateMixin {
}

②Controller内にAnimationControllerのインスタンスを作成

今回は、1秒ごとに処理を何度も行うようにしました。
repeatを使うことで何度もアニメーションを使えるようになりました。

あと、with GetSingleTickerProviderStateMixinを使わなければいけない理由としては、

vsync: this,  のthisを入れられるようにするためです。

controller内の記載内容です。

 late AnimationController animationController;

 @override
  void onInit() {
    super.onInit();
    animationController = AnimationController(
      vsync: this,
      duration: const Duration(
         seconds: 1,
      ),
    )..repeat(reverse: true);
  }

③Screen内に記載

今回は、大きさ1.0倍から1.17倍に大きくなったり、小さくなったりするアニメーションを実装しました。

ScaleTransition(
  scale: controller.animationController.drive(
    Tween<double>(
      begin: 1,
      end: 1.17,
    ),
  ),
  child: ButtonItem(
  onPressed: controller.onTapLevel4,
  text: 'レベル4',
  ),
),

ButtonItemでComponent化していますが、無理にComponent化しなくてもOKです。

button_item.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class ButtonItem extends StatelessWidget {
  const ButtonItem({
    Key? key,
    required this.onPressed,
    required this.text,
  }) : super(key: key);

  final Function() onPressed;
  final String text;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Container(
        width: 280,
        height: 60,
        decoration: const BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(25.0)),
          boxShadow: [
            BoxShadow(
              color: Colors.white,
              spreadRadius: 4,
              blurRadius: 10,
              offset: Offset(0, 3),
            ),
          ],
        ),
        child: Center(
          child: Text(
            text,
            style: const TextStyle(
              fontSize: 25,
              color: CupertinoColors.black,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ),
      style: ElevatedButton.styleFrom(
        primary: Colors.grey.shade100,
        onPrimary: Colors.grey.shade100,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10.0),
        ),
      ),
    );
  }
}

ソースコード

home_screen

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'component/button_item.dart';
import 'home_screen_controller.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //ここで入れることでHomeScreenControllerが使えるようになる!
    final controller = Get.put(HomeScreenController(), tag: '');
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.white,
        leading: IconButton(
          iconSize: 35,
          icon: const Icon(
            Icons.arrow_back_ios,
            color: Colors.blueAccent,
          ),
          onPressed: controller.onTapBack,
        ),
        actions: [
          IconButton(
            onPressed: controller.onTapTrophyScreen,
            iconSize: 40,
            icon: const Icon(
              Icons.flag,
              color: Colors.black,
            ),
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ScaleTransition(
              scale: controller.animationController.drive(
                Tween<double>(
                  begin: 1,
                  end: 1.1,
                ),
              ),
              child: ButtonItem(
                onPressed: controller.onTapLevel1,
                text: 'レベル1',
              ),
            ),
            ScaleTransition(
              scale: controller.animationController.drive(
                Tween<double>(
                  begin: 1,
                  end: 1.13,
                ),
              ),
              child: ButtonItem(
                onPressed: controller.onTapLevel2,
                text: 'レベル2',
              ),
            ),
            ScaleTransition(
              scale: controller.animationController.drive(
                Tween<double>(
                  begin: 1,
                  end: 1.15,
                ),
              ),
              child: ButtonItem(
                onPressed: controller.onTapLevel3,
                text: 'レベル3',
              ),
            ),
            ScaleTransition(
              scale: controller.animationController.drive(
                Tween<double>(
                  begin: 1,
                  end: 1.17,
                ),
              ),
              child: ButtonItem(
                onPressed: controller.onTapLevel4,
                text: 'レベル4',
              ),
            ),
            ScaleTransition(
              scale: controller.animationController.drive(
                Tween<double>(
                  begin: 1,
                  end: 1.2,
                ),
              ),
              child: ButtonItem(
                onPressed: controller.onTapLevel5,
                text: 'レベル5',
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Preferenceの処理などは気にしないでね。。。

Home_screen_controller
import 'package:flutter/animation.dart';
import 'package:get/get.dart';
import '../../preference/shared_preference.dart';
import '../challenge_screen/challenge_screen_1.dart';
import '../challenge_screen/challenge_screen_2.dart';
import '../challenge_screen/challenge_screen_5.dart';

class HomeScreenController extends GetxController
    with GetSingleTickerProviderStateMixin {
  var stage1 = false.obs;
  var stage2 = false.obs;
  var stage3 = false.obs;
  var stage4 = false.obs;
  var stage5 = false.obs;

  late AnimationController animationController;

  @override
  void onInit() {
    super.onInit();
    sharedPreference();
    animationController = AnimationController(
      vsync: this,
      duration: const Duration(
        seconds: 1,
      ),
    )..repeat(reverse: true);
  }

  void onTapBack() {
    Get.back();
  }

  Future<void> sharedPreference() async {
    stage1.value = await Preference().getBool(PreferenceKey.stage1);
    stage2.value = await Preference().getBool(PreferenceKey.stage2);
    stage3.value = await Preference().getBool(PreferenceKey.stage3);
    stage4.value = await Preference().getBool(PreferenceKey.stage4);
    stage5.value = await Preference().getBool(PreferenceKey.stage5);
  }

  void onTapLevel1() {
    Get.to(() => const ChallengeScreen1());
  }

  void onTapLevel2() {
    Get.to(() => const ChallengeScreen2());
  }

  void onTapLevel3() {
    Get.to(() => const ChallengeScreen3());
  }

  void onTapLevel4() {
    Get.to(() => const ChallengeScreen5());
  }

  void onTapLevel5() {
    Get.to(() => const ChallengeScreen5());
  }

  void onTapTrophyScreen() {
    Get.to(
      () => TrophyScreen(
        isClear1: stage1.value,
        isClear2: stage2.value,
        isClear3: stage3.value,
        isClear4: stage4.value,
        isClear5: stage5.value,
      ),
    );
  }
}

参考文献

1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?