Last active
September 25, 2022 13:20
-
-
Save sakiraykurt/1c6f7f25fda6a2ac90f14f289a131bee to your computer and use it in GitHub Desktop.
Flutter animating route pages - PageSwitcherBuilder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() => runApp(const MyApp()); | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
static const String _title = 'Flutter Code Sample'; | |
@override | |
Widget build(BuildContext context) { | |
return const MaterialApp( | |
title: _title, | |
home: FirstPage(), | |
); | |
} | |
} | |
class FirstPage extends StatefulWidget { | |
const FirstPage({Key? key}) : super(key: key); | |
@override | |
State<FirstPage> createState() => FirstPageState(); | |
} | |
class FirstPageState extends State<FirstPage> { | |
@override | |
Widget build(BuildContext context) { | |
return PageSwitcherBuilder( | |
builder: (controller) { | |
final curved = CurvedAnimation( | |
parent: controller, | |
curve: Curves.easeOutCubic, | |
reverseCurve: Curves.easeInCubic); | |
return SlideTransition( | |
position: | |
Tween<Offset>(begin: Offset.zero, end: const Offset(-1.0, 0.0)) | |
.animate(curved), | |
child: Scaffold( | |
backgroundColor: Colors.white, | |
body: Center( | |
child: TextButton.icon( | |
onPressed: () { | |
Navigator.of(context).push( | |
PageSwitcherRoute( | |
controller: controller, | |
page: SlideTransition( | |
position: Tween<Offset>( | |
begin: const Offset(1.0, 0.0), | |
end: Offset.zero, | |
).animate(curved), | |
child: const SecondPage(), | |
), | |
), | |
); | |
}, | |
icon: const Icon(Icons.arrow_forward_rounded), | |
label: const Text( | |
'Go', | |
style: TextStyle(color: Colors.amber), | |
), | |
), | |
), | |
), | |
); | |
}, | |
); | |
} | |
} | |
class SecondPage extends StatelessWidget { | |
const SecondPage({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return PageSwitcherBuilder(builder: (controller) { | |
final curved = CurvedAnimation( | |
parent: controller, | |
curve: Curves.linear, | |
reverseCurve: Curves.linear); | |
return ScaleTransition( | |
scale: Tween<double>(begin: 1.0, end: 1.3).animate(curved), | |
child: Scaffold( | |
backgroundColor: Colors.red, | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
TextButton.icon( | |
onPressed: () { | |
Navigator.of(context).pop(); | |
}, | |
icon: const Icon(Icons.arrow_back), | |
label: const Text( | |
'Return', | |
style: TextStyle(color: Colors.amber), | |
), | |
), | |
TextButton.icon( | |
onPressed: () { | |
Navigator.of(context).push( | |
PageSwitcherRoute( | |
controller: controller, | |
page: FadeTransition( | |
opacity: curved, | |
child: ScaleTransition( | |
scale: Tween<double>(begin: 0.95, end: 1.0) | |
.animate(curved), | |
child: const ThirdPage(), | |
), | |
), | |
), | |
); | |
}, | |
icon: const Icon(Icons.arrow_forward), | |
label: const Text( | |
'Next', | |
style: TextStyle(color: Colors.amber), | |
), | |
), | |
], | |
), | |
), | |
), | |
); | |
}); | |
} | |
} | |
class ThirdPage extends StatelessWidget { | |
const ThirdPage({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
backgroundColor: Colors.purple, | |
body: Center( | |
child: TextButton.icon( | |
onPressed: () { | |
Navigator.of(context).pop(); | |
}, | |
icon: const Icon(Icons.arrow_back), | |
label: const Text( | |
'Return', | |
style: TextStyle(color: Colors.amber), | |
), | |
), | |
), | |
); | |
} | |
} | |
class PageSwitcherBuilder extends StatefulWidget { | |
const PageSwitcherBuilder( | |
{Key? key, | |
required this.builder, | |
this.duration = const Duration(milliseconds: 500), | |
this.reverseDuration = const Duration(milliseconds: 500)}) | |
: super(key: key); | |
final Duration duration; | |
final Duration reverseDuration; | |
final Widget Function(AnimationController controller) builder; | |
@override | |
State<PageSwitcherBuilder> createState() => _PageSwitcherBuilderState(); | |
} | |
class _PageSwitcherBuilderState extends State<PageSwitcherBuilder> | |
with TickerProviderStateMixin { | |
late final AnimationController _controller = AnimationController( | |
vsync: this, | |
duration: widget.duration, | |
reverseDuration: widget.reverseDuration, | |
); | |
@override | |
void dispose() { | |
_controller.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return widget.builder(_controller); | |
} | |
} | |
class PageSwitcherRoute extends PageRouteBuilder { | |
PageSwitcherRoute({ | |
required this.controller, | |
required Widget page, | |
}) : super(pageBuilder: (BuildContext context, Animation<double> animation, | |
Animation<double> secondaryAnimation) { | |
return page; | |
}) { | |
willDisposeAnimationController = false; | |
} | |
@override | |
final AnimationController controller; | |
@override | |
AnimationController createAnimationController() { | |
return controller; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment