|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:flutter/physics.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// Reusable spring route
 | 
					
						
							|  |  |  | class CustomPageRoute extends PageRouteBuilder { | 
					
						
							|  |  |  |   final Widget page; | 
					
						
							|  |  |  |   final AxisDirection direction; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CustomPageRoute({required this.page, this.direction = AxisDirection.right}) | 
					
						
							|  |  |  |       : super( | 
					
						
							|  |  |  |           transitionDuration: const Duration(milliseconds: 1500), | 
					
						
							|  |  |  |           reverseTransitionDuration: const Duration(milliseconds: 500), | 
					
						
							|  |  |  |           pageBuilder: (_, __, ___) => page, | 
					
						
							|  |  |  |           transitionsBuilder: (context, animation, secondaryAnimation, child) { | 
					
						
							|  |  |  |             final spring = SpringDescription(mass: 1, stiffness: 100, damping: 15); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Drive animation with spring
 | 
					
						
							|  |  |  |             final curvedAnimation = animation.drive( | 
					
						
							|  |  |  |               Tween<double>(begin: 0.0, end: 1.0).chain(CurveTween(curve: _SpringCurve(spring))), | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Choose offset based on direction
 | 
					
						
							|  |  |  |             Offset beginOffset; | 
					
						
							|  |  |  |             switch (direction) { | 
					
						
							|  |  |  |               case AxisDirection.left: | 
					
						
							|  |  |  |                 beginOffset = const Offset(-1.0, 0.0); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |               case AxisDirection.right: | 
					
						
							|  |  |  |                 beginOffset = const Offset(1.0, 0.0); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |               case AxisDirection.up: | 
					
						
							|  |  |  |                 beginOffset = const Offset(0.0, -1.0); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |               case AxisDirection.down: | 
					
						
							|  |  |  |                 beginOffset = const Offset(0.0, 1.0); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             final offsetAnimation = Tween<Offset>(begin: beginOffset, end: Offset.zero).animate(curvedAnimation); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return SlideTransition( | 
					
						
							|  |  |  |               position: offsetAnimation, | 
					
						
							|  |  |  |               child: child, | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// Custom spring curve
 | 
					
						
							|  |  |  | class _SpringCurve extends Curve { | 
					
						
							|  |  |  |   final SpringDescription spring; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _SpringCurve(this.spring); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   double transform(double t) { | 
					
						
							|  |  |  |     final sim = SpringSimulation(spring, 0, 1, 0); | 
					
						
							|  |  |  |     return sim.x(t * 1.5); // scaled time
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |