この記事は、株式会社ゆめみの23卒 Advent Calendar 2023のアドベントカレンダーになります!!
色々な種類の記事が投稿されるので、お楽しみに🤗
はじめに
アプリを作る上でどんなアプリがユーザーにとっていいものかを研究するのは個人的には好きですし、作れた時の達成感はすごい嬉しいですね。
今回は画面遷移のアニメーションに着眼点を見つけて、作ってみることにしました。
(作ってみたと言っていますが、ChatGPTに作ってもらい、調整しました💦)
色々なアニメーションを作成してみました
まずはいくつか作成してみたもののデモを表示します。
black out | white out | slide in |
---|---|---|
scale up transition | flip transtion | elatstic transtion |
---|---|---|
diagonal slide transtion | vertical flip transtion | fade through color transition |
---|---|---|
これ使ってみたい!というものがあれば下に実装例を記載しています〜〜😚
それぞれの実装を紹介
blackOut
blackOutを使用すると、画面が黒くなりながら新しい画面に遷移します。
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を使うと、画面が白くなりながら新しい画面に遷移します。
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を使用すると、画面が下から上へスライドしながら現れます。
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を使用すると、画面が小さくから大きくなりながら現れ、同時にフェードインします。
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度回転しながら遷移します。
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を使用すると、ゴムのような効果で画面がズームインします。
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を使用すると、画面が左上から斜めにスライドしながら現れます。
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度回転しながら遷移します。
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を使用すると、指定された色を通してフェードイン/アウトすることで画面遷移を行います。
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卒のメンバーでアドベントカレンダーを作成しています。
新卒のフレッシュな記事がたくさん投稿予定なので、少しでも興味があれば購読いただけると幸いです!!