import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; /// Page transitions, kept in one place so every screen arrives the same way. /// /// Two kinds only. Moving *deeper* (a shift, a document, a timecard) slides /// forward, and the screen behind it slides back a little so the stack reads /// as a stack. Moving *sideways* — between steps of sign-up, or replacing the /// whole screen — cross-fades, because nothing is being pushed onto anything. abstract final class Transitions { static const _forward = Duration(milliseconds: 320); static const _back = Duration(milliseconds: 260); /// Pushed detail screens. static CustomTransitionPage push(GoRouterState state, Widget child) { return CustomTransitionPage( key: state.pageKey, child: child, transitionDuration: _forward, reverseTransitionDuration: _back, transitionsBuilder: (context, animation, secondaryAnimation, child) { final incoming = CurvedAnimation( parent: animation, curve: Curves.easeOutCubic, reverseCurve: Curves.easeInCubic, ); // The outgoing screen eases back rather than sitting still, which is // what gives the push its depth. final outgoing = CurvedAnimation( parent: secondaryAnimation, curve: Curves.easeOutCubic, reverseCurve: Curves.easeInCubic, ); // secondaryAnimation rests at 0 while this page is on top, so the // resting state has to be `begin`. Reversing these two leaves every // pushed screen sitting 12% off to the left. return SlideTransition( position: Tween( begin: Offset.zero, end: const Offset(-0.12, 0), ).animate(outgoing), child: FadeTransition( opacity: Tween(begin: 1.0, end: 0.0).animate(outgoing), child: SlideTransition( position: Tween( begin: const Offset(1, 0), end: Offset.zero, ).animate(incoming), child: child, ), ), ); }, ); } /// Screens that replace what came before: splash, onboarding, sign-in steps. static CustomTransitionPage fade(GoRouterState state, Widget child) { return CustomTransitionPage( key: state.pageKey, child: child, transitionDuration: _forward, reverseTransitionDuration: _back, transitionsBuilder: (context, animation, secondaryAnimation, child) { final curved = CurvedAnimation( parent: animation, curve: Curves.easeOutCubic, ); return FadeTransition( opacity: curved, // A few pixels of rise stops the cross-fade feeling inert. child: SlideTransition( position: Tween( begin: const Offset(0, 0.015), end: Offset.zero, ).animate(curved), child: child, ), ); }, ); } }