5
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】Navigatorでいい感じの遷移アニメーションをつけてみる

Last updated at Posted at 2023-12-22

スクリーンショット 2023-12-22 15.10.56.png

この記事は、株式会社ゆめみの23卒 Advent Calendar 2023のアドベントカレンダーになります!!
色々な種類の記事が投稿されるので、お楽しみに🤗

はじめに

アプリを作る上でどんなアプリがユーザーにとっていいものかを研究するのは個人的には好きですし、作れた時の達成感はすごい嬉しいですね。

今回は画面遷移のアニメーションに着眼点を見つけて、作ってみることにしました。
(作ってみたと言っていますが、ChatGPTに作ってもらい、調整しました💦)

色々なアニメーションを作成してみました

まずはいくつか作成してみたもののデモを表示します。

black out white out slide in
black.gif white.gif slide.gif
scale up transition flip transtion elatstic transtion
scale.gif flip.gif elap.gif
diagonal slide transtion vertical flip transtion fade through color transition
Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.16.11.gif Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.16.54.gif Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.17.42.gif

これ使ってみたい!というものがあれば下に実装例を記載しています〜〜😚

それぞれの実装を紹介

blackOut

blackOutを使用すると、画面が黒くなりながら新しい画面に遷移します。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.09.48.gif

PageRouteBuilder<Object?> blackOut(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionDuration: const Duration(seconds: 1),
    reverseTransitionDuration: const Duration(seconds: 1),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      final color = ColorTween(
        begin: Colors.transparent,
        end: Colors.black,
      ).animate(
        CurvedAnimation(
          parent: animation,
          curve: const Interval(0, 0.5, curve: Curves.easeInOut),
        ),
      );
      final opacity = Tween<double>(
        begin: 0,
        end: 1,
      ).animate(
        CurvedAnimation(
          parent: animation,
          curve: const Interval(0.5, 1, curve: Curves.easeInOut),
        ),
      );
      return AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return Container(
            color: color.value,
            child: Opacity(
              opacity: opacity.value,
              child: child,
            ),
          );
        },
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    blackOut(const SecondScreen()),
  );
},

whiteOut

whitekOutを使うと、画面が白くなりながら新しい画面に遷移します。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.10.36.gif

PageRouteBuilder<Object?> whiteOut(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionDuration: const Duration(seconds: 1),
    reverseTransitionDuration: const Duration(seconds: 1),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      final color = ColorTween(
        begin: Colors.transparent,
        end: Colors.white,
      ).animate(
        CurvedAnimation(
          parent: animation,
          curve: const Interval(0, 0.5, curve: Curves.easeInOut),
        ),
      );
      final opacity = Tween<double>(
        begin: 0,
        end: 1,
      ).animate(
        CurvedAnimation(
          parent: animation,
          curve: const Interval(0.5, 1, curve: Curves.easeInOut),
        ),
      );
      return AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return Container(
            color: color.value,
            child: Opacity(
              opacity: opacity.value,
              child: child,
            ),
          );
        },
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    whiteOut(const SecondScreen()),
  );
},

slideIn

slideInを使用すると、画面が下から上へスライドしながら現れます。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.11.36.gif

PageRouteBuilder<Object?> slideIn(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return screen;
    },
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      const begin = Offset(0, 1);
      const end = Offset.zero;
      final tween = Tween(begin: begin, end: end)
          .chain(CurveTween(curve: Curves.easeInOut));
      final offsetAnimation = animation.drive(tween);
      return SlideTransition(
        position: offsetAnimation,
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    slideIn(const SecondScreen()),
  );
},

scaleUpTransition

scaleUpTransitionを使用すると、画面が小さくから大きくなりながら現れ、同時にフェードインします。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.12.33.gif


PageRouteBuilder<Object?> scaleUpTransition(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return ScaleTransition(
        scale: Tween<double>(begin: 0.0, end: 1.0).animate(
          CurvedAnimation(parent: animation, curve: Curves.fastOutSlowIn),
        ),
        child: FadeTransition(
          opacity: Tween<double>(begin: 0.0, end: 1.0).animate(animation),
          child: child,
        ),
      );
    },
  );
}

onPressed: () {
  Navigator.of(context).push(
    scaleUpTransition(const SecondScreen()),
  );
},

flipTransition

flipTransitionを使用すると、画面がY軸を中心に360度回転しながら遷移します。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.14.41.gif

PageRouteBuilder<Object?> flipTransition(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          final flipAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
            CurvedAnimation(parent: animation, curve: Curves.linear),
          );
          return Transform(
            transform: Matrix4.identity()
              ..setEntry(3, 2, 0.001)
              ..rotateY(2 * 3.14 * flipAnimation.value),
            alignment: Alignment.center,
            child: child,
          );
        },
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    flipTransition(const SecondScreen()),
  );
},

elasticTransition

elasticTransitionを使用すると、ゴムのような効果で画面がズームインします。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.15.10.gif

PageRouteBuilder<Object?> elasticTransition(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      final elasticAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
        CurvedAnimation(parent: animation, curve: Curves.easeOutExpo),
      );
      return ScaleTransition(
        scale: elasticAnimation,
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    elasticTransition(const SecondScreen()),
  );
},

diagonalSlideTransition

diagonalSlideTransitionを使用すると、画面が左上から斜めにスライドしながら現れます。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.16.11.gif

PageRouteBuilder<Object?> diagonalSlideTransition(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      final offsetAnimation = Tween<Offset>(
        begin: const Offset(-1.0, -1.0),
        end: Offset.zero,
      ).animate(animation);

      return SlideTransition(
        position: offsetAnimation,
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    diagonalSlideTransition(const SecondScreen()),
  );
},

verticalFlipTransition

verticalFlipTransitionを使用すると、画面がX軸を中心に360度回転しながら遷移します。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.16.54.gif

PageRouteBuilder<Object?> verticalFlipTransition(Widget screen) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      final flipAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
        CurvedAnimation(parent: animation, curve: Curves.linear),
      );
      return AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return Transform(
            alignment: Alignment.center,
            transform: Matrix4.identity()
              ..setEntry(3, 2, 0.001)
              ..rotateX(2 * pi * flipAnimation.value),
            child: child,
          );
        },
        child: child,
      );
    },
  );
}
onPressed: () {
  Navigator.of(context).push(
    verticalFlipTransition(const SecondScreen()),
  );
},

fadeThroughColorTransition

fadeThroughColorTransitionを使用すると、指定された色を通してフェードイン/アウトすることで画面遷移を行います。

Simulator Screen Recording - iPhone 15 Pro - 2023-12-22 at 14.17.42.gif

PageRouteBuilder<Object?> fadeThroughColorTransition(
    Widget screen, Color transitionColor) {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => screen,
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      final slowAnimation = CurvedAnimation(
        parent: animation,
        curve: Curves.easeOut,
      );
      return AnimatedBuilder(
        animation: slowAnimation,
        builder: (context, child) {
          return Stack(
            children: [
              FadeTransition(
                opacity:
                    Tween<double>(begin: 1.0, end: 0.0).animate(slowAnimation),
                child: Container(color: transitionColor),
              ),
              FadeTransition(
                opacity:
                    Tween<double>(begin: 0.0, end: 1.0).animate(slowAnimation),
                child: child,
              ),
            ],
          );
        },
        child: child,
      );
    },
  );
}

onPressed: () {
  Navigator.of(context).push(
    fadeThroughColorTransition(
      const SecondScreen(),
      Colors.white,
    ),
  );
},

最後に

こちらにリポジトリを載せておきます。

アニメーションについての研究はまだまだできそうな気がするので色々な場面でも使っていこうと思いました!

ちょっとした宣伝

株式会社ゆめみの23卒のメンバーでアドベントカレンダーを作成しています。
新卒のフレッシュな記事がたくさん投稿予定なので、少しでも興味があれば購読いただけると幸いです!!

YUMEMI New Grad Advent Calendar 2023
5
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
5
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?