On Android API we can use
overridePendingTransition(int enterAnim, int exitAnim)
to define the enter and exit transitions.
How to do it in Flutter?
I have implemented this code
class SlideLeftRoute extends PageRouteBuilder {
final Widget enterWidget;
SlideLeftRoute({this.enterWidget})
: super(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return enterWidget;
},
transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child
);
},
);
}
but it only defines the enter transition. How can i define de exit transition?
UPDATE
Imagine that i have two screens (Screen1 and Screen2), when i execute
Navigator.push(
context, SlideLeftRoute(enterWidget: Screen2()));
i'd like to apply an animation to both Screen1 and Screen2 and not only to Screen2
The correct way of achieving this is to use the secondaryAnimation parameter that is given in the transitionBuilder of a PageRouteBuilder object.
Here you can read more about the secondaryAnimation parameter in the documentation in the flutter/lib/src/widgets/routes.dart file in the flutter sdk:
///
/// When the [Navigator] pushes a route on the top of its stack, the
/// [secondaryAnimation] can be used to define how the route that was on
/// the top of the stack leaves the screen. Similarly when the topmost route
/// is popped, the secondaryAnimation can be used to define how the route
/// below it reappears on the screen. When the Navigator pushes a new route
/// on the top of its stack, the old topmost route's secondaryAnimation
/// runs from 0.0 to 1.0. When the Navigator pops the topmost route, the
/// secondaryAnimation for the route below it runs from 1.0 to 0.0.
///
/// The example below adds a transition that's driven by the
/// [secondaryAnimation]. When this route disappears because a new route has
/// been pushed on top of it, it translates in the opposite direction of
/// the new route. Likewise when the route is exposed because the topmost
/// route has been popped off.
///
/// ```dart
/// transitionsBuilder: (
/// BuildContext context,
/// Animation<double> animation,
/// Animation<double> secondaryAnimation,
/// Widget child,
/// ) {
/// return SlideTransition(
/// position: AlignmentTween(
/// begin: const Offset(0.0, 1.0),
/// end: Offset.zero,
/// ).animate(animation),
/// child: SlideTransition(
/// position: TweenOffset(
/// begin: Offset.zero,
/// end: const Offset(0.0, 1.0),
/// ).animate(secondaryAnimation),
/// child: child,
/// ),
/// );
/// }
/// ```
This is a working example using the secondaryAnimation parameter:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => Page1(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
final Tween<Offset> offsetTween = Tween<Offset>(begin: Offset(0.0, 0.0), end: Offset(-1.0, 0.0));
final Animation<Offset> slideOutLeftAnimation = offsetTween.animate(secondaryAnimation);
return SlideTransition(position: slideOutLeftAnimation, child: child);
},
);
} else {
// handle other routes here
return null;
}
},
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
backgroundColor: Colors.blue,
body: Center(
child: RaisedButton(
onPressed: () => Navigator.push(
context,
PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => Page2(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
final Tween<Offset> offsetTween = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0));
final Animation<Offset> slideInFromTheRightAnimation = offsetTween.animate(animation);
return SlideTransition(position: slideInFromTheRightAnimation, child: child);
},
),
),
child: Text("Go to Page 2"),
),
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2"), backgroundColor: Colors.green),
backgroundColor: Colors.green,
body: Center(child: RaisedButton(onPressed: () => Navigator.pop(context), child: Text("Back to Page 1"))),
);
}
}
Result:
Screenshot (Null Safe):
I used a different way, but similar logic provided by diegodeveloper
Full code:
void main() => runApp(MaterialApp(home: Page1()));
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(title: Text('Page 1')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.push(
context,
MyCustomPageRoute(
parent: this,
builder: (context) => Page2(),
),
),
child: Text('2nd Page'),
),
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueGrey,
appBar: AppBar(title: Text('Page 2')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Back'),
),
),
);
}
}
class MyCustomPageRoute<T> extends MaterialPageRoute<T> {
final Widget parent;
MyCustomPageRoute({
required this.parent,
required WidgetBuilder builder,
RouteSettings? settings,
}) : super(builder: builder, settings: settings);
#override
Widget buildTransitions(_, Animation<double> animation, __, Widget child) {
var anim1 = Tween<Offset>(begin: Offset.zero, end: Offset(-1.0, 0.0)).animate(animation);
var anim2 = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset.zero).animate(animation);
return Stack(
children: <Widget>[
SlideTransition(position: anim1, child: parent),
SlideTransition(position: anim2, child: child),
],
);
}
}
Good question , the PageRouteBuilder use an AnimationController by default to handle the animation transition so, when you dismiss your view, it just call 'reverse' method from the animationController and you will see the same animation you are using but in reverse.
In case you want to change the animation when you dismiss your view you can do it checking the status of the current animation and compare with AnimationStatus.reverse
This is your code with a Fade animation when it's in reverse.
class SlideLeftRoute extends PageRouteBuilder {
final Widget enterWidget;
SlideLeftRoute({this.enterWidget})
: super(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return enterWidget;
},
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
if (animation.status == AnimationStatus.reverse) {
//do your dismiss animation here
return FadeTransition(
opacity: animation,
child: child,
);
} else {
return SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child);
}
},
);
}
WORKAROUND
class SlideLeftRoute extends PageRouteBuilder {
final Widget enterWidget;
final Widget oldWidget;
SlideLeftRoute({this.enterWidget, this.oldWidget})
: super(
transitionDuration: Duration(milliseconds: 600),
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return enterWidget;
},
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return Stack(
children: <Widget>[
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-1.0, 0.0),
).animate(animation),
child: oldWidget),
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: enterWidget)
],
);
});
}
Usage:
Navigator.of(context)
.push(SlideLeftRoute(enterWidget: Page2(), oldWidget: this));
#janosch's answer worked the best for me (so be sure to upvote him if this works for you), but #bihire boris's point about not being able to have more than 2 page routes in a navigation stack was true.
What worked for me was this:
class SlidingPageRouteBuilder extends PageRouteBuilder {
SlidingPageRouteBuilder({
required RoutePageBuilder pageBuilder,
}) : super(
transitionDuration: const Duration(milliseconds: 300),
reverseTransitionDuration: const Duration(milliseconds: 300),
pageBuilder: pageBuilder,
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
final pushingNext =
secondaryAnimation.status == AnimationStatus.forward;
final poppingNext =
secondaryAnimation.status == AnimationStatus.reverse;
final pushingOrPoppingNext = pushingNext || poppingNext;
late final Tween<Offset> offsetTween = pushingOrPoppingNext
? Tween<Offset>(
begin: const Offset(0.0, 0.0), end: const Offset(-1.0, 0.0))
: Tween<Offset>(
begin: const Offset(1.0, 0.0), end: const Offset(0.0, 0.0));
late final Animation<Offset> slidingAnimation = pushingOrPoppingNext
? offsetTween.animate(secondaryAnimation)
: offsetTween.animate(animation);
return SlideTransition(position: slidingAnimation, child: child);
},
);
}
And the implementation:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: Routes.first,
onGenerateRoute: Routes.generateRoutes,
},
);
}
}
class Routes {
static const String first = '/first';
static const String second = '/second';
static Route<dynamic>? generateRoutes(RouteSettings settings) {
switch (settings.name) {
case first:
return SlidingPageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const FirstPage(),
);
case second:
return SlidingPageRouteBuilder(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
const SecondPage(),
);
default:
return null;
}
}
}
Result:
The one downside to this method (and all other methods I've seen) is that the user cannot drag their finger along the left edge of the screen towards the right to pop, in the way that a MaterialPageRoute lets you.
There is another way to do it. The problem of initState() getting called in oldWidget won't be there anymore.
void main() => runApp(MaterialApp(theme: ThemeData.dark(), home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
body: RaisedButton(
child: Text("Next"),
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (c, a1, a2) => Page2(),
transitionsBuilder: (context, anim1, anim2, child) {
return SlideTransition(
position: Tween<Offset>(end: Offset(0, 0), begin: Offset(1, 0)).animate(anim1),
child: Page2(),
);
},
),
);
},
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2")),
body: RaisedButton(
child: Text("Back"),
onPressed: () => Navigator.pop(context),
),
);
}
}
Related
Is there a way to set an animation between two specific pages? I'm using onGenerateRoute to change animations between pages, but it can only filter through the page it's being navigated to.
Example: I have PageA, PageB and PageC, i can change the navigation animation when i'm navigating to PageC, but it doesn't matter if i'm navigating from PageA or PageB, the animation will always be the same.
What i'm asking for is if there is a way to make a custom animation specifically when i'm navigating between PageA and PageC and PageB and PageC.
Create Animated Navigation like this:
import 'package:flutter/material.dart';
void main() {
runApp(
const MaterialApp(
home: Page1(),
),
);
}
class Page1 extends StatelessWidget {
const Page1({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(_createRoute());
},
child: const Text('Go!'),
),
),
);
}
}
Route _createRoute() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => const Page2(),
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));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}
class Page2 extends StatelessWidget {
const Page2({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text('Page 2'),
),
);
}
}
I want to use animated page route on my flutter project. Now all of my routes are Named Route and I don't wanna change them. Is there any way I can use Page Route Animation with named route? Like: If I am going from PageOne() to PageTwo() using Navigator.of(context).pushNamed(PageTwo.routename), I don't wanna see default transition, May be I want to use scale animation or fade animation. Is there any way to do that?
onTap: () {
Navigator.of(context).pushNamed(
ProductsSearch.routeName,
arguments: ScreenArguments(null, null, null, null, null, null, true, false),
);
},
As your Question I have solved this demo answer try once it will work .
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: HomePage(),
onGenerateRoute: (RouteSettings settings) {
final SecondHome args = settings.arguments;
switch (settings.name) {
case '/':
return SlideRightRoute(widget:HomePage());
break;
case '/second':
return
SlideRightRoute(widget:SecondHome(args.data1,args.data2,args.boolvalue));
break;
}
},
),
);
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: new Center(
child: RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed(
'/second',
arguments:SecondHome("data1","data2",true),
);
},
child: Text('Second Home'),
),
),
);
}
}
class SecondHome extends StatelessWidget {
String data1;
String data2;
bool boolvalue;
SecondHome(this.data1,this.data2,this.boolvalue);
#override
Widget build(BuildContext context) {
print("Secoendhomedata${data1}");
return Scaffold(
appBar: AppBar(
title: Text('Second Home'),
),
body: new Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}
class SlideRightRoute extends PageRouteBuilder {
final Widget widget;
SlideRightRoute({this.widget})
: super(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return widget;
},
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return new SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child,
);
},
);
}
I'm having this weird issue that when I navigate to a new route, a text I put on the destination page doesn't show. But other elements do.
here is the implementation on my transition:
class BouncyPageRoute extends PageRouteBuilder {
final Widget destination;
BouncyPageRoute({this.destination})
: super(
transitionDuration: Duration(milliseconds: 600),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
animation =
CurvedAnimation(parent: animation, curve: Curves.elasticInOut);
return ScaleTransition(
scale: animation,
child: child,
alignment: Alignment.center,
);
},
pageBuilder: (context, animation, secondaryAnimation) {
return destination;
},
);
}
The destination page implementation:
import 'package:flutter/material.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
FlutterLogo(),
Text(" can you see meeee??"),
],
),
),
),
);
}
}
you can checkout the project on github git#github.com:folivi/flutter_transition_issue.git
I'm on the flutter 1.22 beta branch.
What I'm I doin't wrong?
thank you for your help
I have the same problem when I set the transition duration to 2000, but it works when I set it at around 1500. So try to adjust the transition duration.
I'm setting my routes and transition animations through onGenerateRoute which is working great except I want differents transition animations depending on a condition (on choosen path for example) :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
Page1(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(-1.0, 0.0),
).animate(secondaryAnimation), // Here I want to have differents transitions
child: child,
);
},
);
} else if (settings.name == '/second') {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
Page2(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0), end: Offset.zero)
.animate(animation),
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, 1.0),
).animate(secondaryAnimation),
child: child,
));
},
);
} else if (settings.name == '/third') {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
Page3(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 1.0), end: Offset.zero)
.animate(animation),
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, 1.0),
).animate(secondaryAnimation),
child: child,
));
},
);
} else {
return null;
}
},
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1"), backgroundColor: Colors.blue),
backgroundColor: Colors.blue,
body: Column(
children: [
Center(
child: RaisedButton(
onPressed: () => Navigator.pushNamed(context, '/second'),
child: Text("Go to Page 2 with exit transition slide left"),
),
),
Center(
child: RaisedButton(
onPressed: () => Navigator.pushNamed(context, '/third'),
child: Text("Go to Page 3 with transition slide top"),
),
),
],
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2"), backgroundColor: Colors.green),
backgroundColor: Colors.green,
body: Center(
child: RaisedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("Go back to page 1"))),
);
}
}
class Page3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 3"), backgroundColor: Colors.yellow),
backgroundColor: Colors.yellow,
body: Center(
child: RaisedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("Go back to page 1"))),
);
}
}
See codePen here
As the exit transition animation (via secondaryAnimation) is set before the screen is displayed, I can't change the animation dynamically depending on the button clicked. How can I achieve that ?
(RouteSettings settings) {
final transition = settings.arguments as String;
if (settings.name == '/') {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) =>
Page1(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
switch (transition) {
case 'firstTransition':
secondaryAnimation = //first animation
break;
case 'secondTransition':
secondaryAnimation = //second animation
break;
}
return SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(-1.0, 0.0),
).animate(secondaryAnimation), // Here I want to have differents transitions
child: child,
);
},
);
How can I create a page that slides from the bottom of the screen and when it passes a certain threshold automatically fills the screen?
Something like this:
Consider using DraggableScrollableSheet class or sliding up panel package
You can use PageRouteBuilder to build your own navigator transitions.
This is the CustomPageRouteBuilder class as you need, and you can change it into other transitons like scale fade rotate, etc.
class CustomPageRouteBuilder<T> extends PageRouteBuilder<T> {
CustomPageRouteBuilder({
this.widget,
})
: assert(widget != null),
super(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return widget;
},
transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
final Widget transition = SlideTransition(
position: Tween<Offset>(
begin: Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: Offset(0.0, -0.7),
).animate(secondaryAnimation),
child: child,
),
);
return transition;
},
);
final Widget widget;
}
And how to use:
Navigator.push(
context,
CustomPageRouteBuilder(
widget: SecondPage(),
),
);
You can check the sample below:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.red,
child: Center(
child: Text(
'First Page',
style: TextStyle(
color: Colors.white,
fontSize: 24.0,
),
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
onPressed: () {
Navigator.push(
context,
CustomPageRouteBuilder(
widget: SecondPage(),
),
);
},
),
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.blue,
child: Center(
child: Text(
'Second Page',
style: TextStyle(
color: Colors.white,
fontSize: 24.0,
),
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
onPressed: () {
Navigator.pop(context);
},
),
);
}
}
class CustomPageRouteBuilder<T> extends PageRouteBuilder<T> {
CustomPageRouteBuilder({
this.widget,
})
: assert(widget != null),
super(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return widget;
},
transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
final Widget transition = SlideTransition(
position: Tween<Offset>(
begin: Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: Offset(0.0, -0.7),
).animate(secondaryAnimation),
child: child,
),
);
return transition;
},
);
final Widget widget;
}
I would recommend the PageView widget, you can see more here and view the documentation.
Using the scrollDirection property, you can set it to vertical so that you can swipe up to reveal a new page and you can swipe down to go back.