85 lines
3.0 KiB
Dart
85 lines
3.0 KiB
Dart
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<T> push<T>(GoRouterState state, Widget child) {
|
|
return CustomTransitionPage<T>(
|
|
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<T> fade<T>(GoRouterState state, Widget child) {
|
|
return CustomTransitionPage<T>(
|
|
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,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|