Separate Route and PerformanceRoute
This patch prepares us to create routes that control their performances more closely.
This commit is contained in:
parent
90d47520fd
commit
30d16e2426
@ -41,6 +41,15 @@ abstract class PerformanceView {
|
|||||||
void addStatusListener(PerformanceStatusListener listener);
|
void addStatusListener(PerformanceStatusListener listener);
|
||||||
/// Stops calling the listener every time the status of the performance changes
|
/// Stops calling the listener every time the status of the performance changes
|
||||||
void removeStatusListener(PerformanceStatusListener listener);
|
void removeStatusListener(PerformanceStatusListener listener);
|
||||||
|
|
||||||
|
/// The current status of this animation
|
||||||
|
PerformanceStatus get status;
|
||||||
|
|
||||||
|
/// Whether this animation is stopped at the beginning
|
||||||
|
bool get isDismissed => status == PerformanceStatus.dismissed;
|
||||||
|
|
||||||
|
/// Whether this animation is stopped at the end
|
||||||
|
bool get isCompleted => status == PerformanceStatus.completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A timeline that can be reversed and used to update [Animatable]s.
|
/// A timeline that can be reversed and used to update [Animatable]s.
|
||||||
@ -51,7 +60,7 @@ abstract class PerformanceView {
|
|||||||
/// may also take direct control of the timeline by manipulating [progress], or
|
/// may also take direct control of the timeline by manipulating [progress], or
|
||||||
/// [fling] the timeline causing a physics-based simulation to take over the
|
/// [fling] the timeline causing a physics-based simulation to take over the
|
||||||
/// progression.
|
/// progression.
|
||||||
class Performance implements PerformanceView {
|
class Performance extends PerformanceView {
|
||||||
Performance({ this.duration, double progress }) {
|
Performance({ this.duration, double progress }) {
|
||||||
_timeline = new SimulationStepper(_tick);
|
_timeline = new SimulationStepper(_tick);
|
||||||
if (progress != null)
|
if (progress != null)
|
||||||
@ -94,16 +103,9 @@ class Performance implements PerformanceView {
|
|||||||
return timing != null ? timing.transform(progress, _curveDirection) : progress;
|
return timing != null ? timing.transform(progress, _curveDirection) : progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this animation is stopped at the beginning
|
|
||||||
bool get isDismissed => status == PerformanceStatus.dismissed;
|
|
||||||
|
|
||||||
/// Whether this animation is stopped at the end
|
|
||||||
bool get isCompleted => status == PerformanceStatus.completed;
|
|
||||||
|
|
||||||
/// Whether this animation is currently animating in either the forward or reverse direction
|
/// Whether this animation is currently animating in either the forward or reverse direction
|
||||||
bool get isAnimating => _timeline.isAnimating;
|
bool get isAnimating => _timeline.isAnimating;
|
||||||
|
|
||||||
/// The current status of this animation
|
|
||||||
PerformanceStatus get status {
|
PerformanceStatus get status {
|
||||||
if (!isAnimating && progress == 1.0)
|
if (!isAnimating && progress == 1.0)
|
||||||
return PerformanceStatus.completed;
|
return PerformanceStatus.completed;
|
||||||
|
@ -131,7 +131,7 @@ class Dialog extends StatelessComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DialogRoute extends Route {
|
class _DialogRoute extends PerformanceRoute {
|
||||||
_DialogRoute({ this.completer, this.builder });
|
_DialogRoute({ this.completer, this.builder });
|
||||||
|
|
||||||
final Completer completer;
|
final Completer completer;
|
||||||
|
@ -256,7 +256,6 @@ class DragRoute extends Route {
|
|||||||
bool get ephemeral => true;
|
bool get ephemeral => true;
|
||||||
bool get modal => false;
|
bool get modal => false;
|
||||||
bool get opaque => false;
|
bool get opaque => false;
|
||||||
Duration get transitionDuration => const Duration();
|
|
||||||
|
|
||||||
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
|
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
|
||||||
return new Positioned(
|
return new Positioned(
|
||||||
|
@ -71,13 +71,6 @@ class NavigatorState extends State<Navigator> {
|
|||||||
push(new PageRoute(builder));
|
push(new PageRoute(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _insertRoute(Route route) {
|
|
||||||
_history.insert(_currentPosition, route);
|
|
||||||
route._onDismissed = _handleRouteDismissed;
|
|
||||||
route._onRemoveRoute = _handleRemoveRoute;
|
|
||||||
route.didPush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void push(Route route) {
|
void push(Route route) {
|
||||||
assert(!_debugCurrentlyHaveRoute(route));
|
assert(!_debugCurrentlyHaveRoute(route));
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -119,13 +112,18 @@ class NavigatorState extends State<Navigator> {
|
|||||||
return index >= 0 && index <= _currentPosition;
|
return index >= 0 && index <= _currentPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleRouteDismissed(Route route) {
|
void _didDismissRoute(Route route) {
|
||||||
assert(_history.contains(route));
|
assert(_history.contains(route));
|
||||||
if (_history.lastIndexOf(route) <= _currentPosition)
|
if (_history.lastIndexOf(route) <= _currentPosition)
|
||||||
popRoute(route);
|
popRoute(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleRemoveRoute(Route route) {
|
void _insertRoute(Route route) {
|
||||||
|
_history.insert(_currentPosition, route);
|
||||||
|
route.didPush(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _removeRoute(Route route) {
|
||||||
assert(_history.contains(route));
|
assert(_history.contains(route));
|
||||||
setState(() {
|
setState(() {
|
||||||
_history.remove(route);
|
_history.remove(route);
|
||||||
@ -165,33 +163,7 @@ class NavigatorState extends State<Navigator> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
abstract class Route {
|
abstract class Route {
|
||||||
Route() {
|
|
||||||
_performance = createPerformance();
|
|
||||||
}
|
|
||||||
|
|
||||||
PerformanceView get performance => _performance?.view;
|
|
||||||
Performance _performance;
|
|
||||||
_RouteCallback _onDismissed;
|
|
||||||
_RouteCallback _onRemoveRoute;
|
|
||||||
|
|
||||||
Performance createPerformance() {
|
|
||||||
Duration duration = transitionDuration;
|
|
||||||
if (duration > Duration.ZERO) {
|
|
||||||
return new Performance(duration: duration)
|
|
||||||
..addStatusListener((PerformanceStatus status) {
|
|
||||||
if (status == PerformanceStatus.dismissed) {
|
|
||||||
if (_onDismissed != null)
|
|
||||||
_onDismissed(this);
|
|
||||||
if (_onRemoveRoute != null)
|
|
||||||
_onRemoveRoute(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If hasContent is true, then the route represents some on-screen state.
|
/// If hasContent is true, then the route represents some on-screen state.
|
||||||
///
|
///
|
||||||
/// If hasContent is false, then no performance will be created, and the values of
|
/// If hasContent is false, then no performance will be created, and the values of
|
||||||
@ -242,32 +214,69 @@ abstract class Route {
|
|||||||
/// cover the entire application surface or are in any way semi-transparent.
|
/// cover the entire application surface or are in any way semi-transparent.
|
||||||
bool get opaque => false;
|
bool get opaque => false;
|
||||||
|
|
||||||
/// If this is set to a non-zero [Duration], then an [Performance]
|
PerformanceView get performance => null;
|
||||||
/// object, available via the performance field, will be created when the
|
bool get isActuallyOpaque => (performance == null || performance.isCompleted) && opaque;
|
||||||
/// route is first built, using the duration described here.
|
|
||||||
Duration get transitionDuration => Duration.ZERO;
|
|
||||||
|
|
||||||
bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque;
|
|
||||||
|
|
||||||
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance);
|
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance);
|
||||||
|
|
||||||
void didPush() {
|
NavigatorState _navigator;
|
||||||
_performance?.forward();
|
|
||||||
|
void didPush(NavigatorState navigator) {
|
||||||
|
assert(_navigator == null);
|
||||||
|
_navigator = navigator;
|
||||||
|
assert(_navigator != null);
|
||||||
|
performance?.addStatusListener(_handlePerformanceStatusChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void didPop([dynamic result]) {
|
void didPop([dynamic result]) {
|
||||||
_performance?.reverse();
|
assert(_navigator != null);
|
||||||
if (performance == null && _onRemoveRoute != null)
|
if (performance == null)
|
||||||
_onRemoveRoute(this);
|
_navigator._removeRoute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handlePerformanceStatusChanged(PerformanceStatus status) {
|
||||||
|
if (status == PerformanceStatus.dismissed) {
|
||||||
|
_navigator._didDismissRoute(this);
|
||||||
|
_navigator._removeRoute(this);
|
||||||
|
_navigator = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString() => '$runtimeType()';
|
String toString() => '$runtimeType()';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class PerformanceRoute extends Route {
|
||||||
|
PerformanceView get performance => _performance?.view;
|
||||||
|
Performance _performance;
|
||||||
|
|
||||||
|
Performance createPerformance() {
|
||||||
|
Duration duration = transitionDuration;
|
||||||
|
assert(duration >= Duration.ZERO);
|
||||||
|
return new Performance(duration: duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
Duration get transitionDuration;
|
||||||
|
|
||||||
|
bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque;
|
||||||
|
|
||||||
|
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance);
|
||||||
|
|
||||||
|
void didPush(NavigatorState navigator) {
|
||||||
|
_performance = createPerformance();
|
||||||
|
super.didPush(navigator);
|
||||||
|
_performance?.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
void didPop([dynamic result]) {
|
||||||
|
_performance?.reverse();
|
||||||
|
super.didPop(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Duration _kTransitionDuration = const Duration(milliseconds: 150);
|
const Duration _kTransitionDuration = const Duration(milliseconds: 150);
|
||||||
const Point _kTransitionStartPoint = const Point(0.0, 75.0);
|
const Point _kTransitionStartPoint = const Point(0.0, 75.0);
|
||||||
|
|
||||||
class PageRoute extends Route {
|
class PageRoute extends PerformanceRoute {
|
||||||
PageRoute(this.builder);
|
PageRoute(this.builder);
|
||||||
|
|
||||||
final RouteBuilder builder;
|
final RouteBuilder builder;
|
||||||
|
@ -117,7 +117,7 @@ class MenuPosition {
|
|||||||
final double left;
|
final double left;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MenuRoute extends Route {
|
class _MenuRoute extends PerformanceRoute {
|
||||||
_MenuRoute({ this.completer, this.position, this.builder, this.level });
|
_MenuRoute({ this.completer, this.position, this.builder, this.level });
|
||||||
|
|
||||||
final Completer completer;
|
final Completer completer;
|
||||||
|
@ -97,7 +97,7 @@ class SnackBar extends StatelessComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SnackBarRoute extends Route {
|
class _SnackBarRoute extends PerformanceRoute {
|
||||||
_SnackBarRoute({ this.content, this.actions });
|
_SnackBarRoute({ this.content, this.actions });
|
||||||
|
|
||||||
final Widget content;
|
final Widget content;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user