Flutter 에서는 MaterialPageRoute를 이용하여 각 플랫폼에 맞는 라우팅을 제공하고 있습니다. 하지만, 요구사항에 따라서 여러가지 네비게이션 효과를 구현해야 되는 경우가 있는데요. 이러한 경우에 네비게이션에 애니메이션 효과를 줄 수 있습니다.
가장 기본적으로 네비게이션을 위한 두개의 페이지 위젯을 제작해보겠습니다.
//main.dart
import ...
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(
home: App(),
);
}
}
페이지 이동은 App.dart로부터 시작됩니다. 간단하게 Text와 ElevatedButton위젯으로 구현해보겠습니다.
//app.dart
import ...
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Animation Page Routing"),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("첫번째 페이지"),
ElevatedButton(
onPressed: () {
// 네비게이션 함수
},
child: const Text("두번째 페이지로"))
],
)),
);
}
}
페이지 이동 후 도달하게 되는 페이지입니다. 이 페이지에서는 간단하게 뒤로가기 버튼 활성화를 위해 AppBar, 두번째 페이지를 의미하는 Text 위젯만 존재합니다.
import ...
class Second extends StatelessWidget {
const Second({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text("두번째 페이지"),
),
);
}
}
PageRouteBuilder는 간단하게 네비게이션 애니메이션을 줄 수 있는 위젯입니다. 이를 이용해서 여러 형식의 네비게이션을 한번 만들어 보겠습니다.
import ...
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Animation Page Routing"),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("첫번째 페이지"),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const Second(),
));
},
child: const Text("두번째 페이지로"))
],
)),
);
}
}
아무런 효과도 지정하지 않은 Plain 형식의 PageRouteBuilder입니다. 이렇게 되면 페이지가 바로바로 이동하게 됩니다.
이제 Slide Animation을 가진 네비게이션을 생성해보겠습니다. PageRouteBuilder에 큰 장점은 이것을 너무나 쉽게 만들 수 있게 해줍니다.
import 'package:flutter/material.dart';
import 'package:flutter_animation_navigation/src/pages/second.dart';
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Animation Page Routing"),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("첫번째 페이지"),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const Second(),
// transition 정의
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, -1.0);
const end = Offset.zero;
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation, child: child);
},
));
},
child: const Text("두번째 페이지로"))
],
)),
);
}
}
transitionBuilder를 통해 여러가지 애니메이션을 지정할 수 있습니다. 지금 애니메이션은 아래에서 위로 페이지가 등장하게 됩니다. Offset을 조절하면 여러 방향에서 페이지를 이동시킬 수 있습니다.
기본적인 Transition은 동일한 속도로 페이지가 이동하는데, 만약 속도의 변화를 곡선의 형태로 나타내고 싶다면 Curve를 이용할 수 있습니다. 점점 빨라지거나 점점 느려지는 것을 구현할 수 있습니다.
import ...
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Animation Page Routing"),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("첫번째 페이지"),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const Second(),
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end)
.chain(CurveTween(curve: curve));
final tweenAnimation = animation.drive(tween);
return SlideTransition(
position: tweenAnimation, child: child);
},
));
},
child: const Text("두번째 페이지로"))
],
)),
);
}
}
Curve의 종류를 변경하면 여러가지 속도 곡선을 이용할 수 있습니다.
Fade 효과를 나타내기 위해서는 Fade Transition을 이용할 수 있습니다.
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Animation Page Routing"),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("첫번째 페이지"),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const Second(),
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return FadeTransition(opacity: animation, child: child);
},
));
},
child: const Text("두번째 페이지로"))
],
)),
);
}
}
FadeTransition 위젯은 Fade 효과를 표현할 수 있습니다.