diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index de0a0a03fd..45caafc4b4 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -899,6 +899,9 @@ class IgnorePointer extends OneChildRenderObjectWidget { } } + +// UTILITY NODES + class MetaData extends OneChildRenderObjectWidget { MetaData({ Key key, Widget child, this.metaData }) : super(key: key, child: child); @@ -911,3 +914,12 @@ class MetaData extends OneChildRenderObjectWidget { renderObject.metaData = metaData; } } + +class KeyedSubtree extends StatelessComponent { + KeyedSubtree({ Key key, this.child }) + : super(key: key); + + final Widget child; + + Widget build(BuildContext context) => child; +} \ No newline at end of file diff --git a/packages/flutter/lib/src/widgets/dialog.dart b/packages/flutter/lib/src/widgets/dialog.dart index 2e83515ca0..b9b24ad890 100644 --- a/packages/flutter/lib/src/widgets/dialog.dart +++ b/packages/flutter/lib/src/widgets/dialog.dart @@ -140,7 +140,7 @@ class DialogRoute extends Route { Duration get transitionDuration => _kTransitionDuration; bool get opaque => false; - Widget build(Key key, NavigatorState navigator) { + Widget build(NavigatorState navigator, WatchableAnimationPerformance nextRoutePerformance) { return new FadeTransition( performance: performance, opacity: new AnimatedValue(0.0, end: 1.0, curve: easeOut), diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index fe600aeb8f..f5552372a0 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -5,6 +5,7 @@ import 'dart:collection'; import 'dart:sky' as sky; +import 'package:sky/animation.dart'; import 'package:sky/rendering.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/binding.dart'; @@ -199,10 +200,10 @@ class DragRoute extends Route { bool get ephemeral => true; bool get modal => false; - - Duration get transitionDuration => const Duration(); bool get opaque => false; - Widget build(Key key, NavigatorState navigator) { + Duration get transitionDuration => const Duration(); + + Widget build(NavigatorState navigator, WatchableAnimationPerformance nextRoutePerformance) { return new Positioned( left: _lastOffset.dx, top: _lastOffset.dy, diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index b22ef6c082..c77f365778 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -118,6 +118,7 @@ class NavigatorState extends State { Widget build(BuildContext context) { List visibleRoutes = new List(); bool alreadyInsertModalBarrier = false; + WatchableAnimationPerformance nextPerformance; for (int i = _history.length-1; i >= 0; i -= 1) { Route route = _history[i]; if (!route.hasContent) { @@ -133,9 +134,12 @@ class NavigatorState extends State { _history.remove(route); }); }; - Key key = new ObjectKey(route); - Widget widget = route.build(key, this); - visibleRoutes.add(widget); + visibleRoutes.add( + new KeyedSubtree( + key: new ObjectKey(route), + child: route.build(this, nextPerformance) + ) + ); if (route.isActuallyOpaque) break; assert(route.modal || route.ephemeral); @@ -146,6 +150,7 @@ class NavigatorState extends State { )); alreadyInsertModalBarrier = true; } + nextPerformance = route.performance; } return new Focus(child: new Stack(visibleRoutes.reversed.toList())); } @@ -238,7 +243,7 @@ abstract class Route { bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque; - Widget build(Key key, NavigatorState navigator); + Widget build(NavigatorState navigator, WatchableAnimationPerformance nextRoutePerformance); void didPop([dynamic result]) { if (performance == null && _onDismissed != null) _onDismissed(); @@ -256,14 +261,12 @@ class PageRoute extends Route { final RouteBuilder builder; bool get opaque => true; - Duration get transitionDuration => _kTransitionDuration; - Widget build(Key key, NavigatorState navigator) { + Widget build(NavigatorState navigator, WatchableAnimationPerformance nextRoutePerformance) { // TODO(jackson): Hit testing should ignore transform // TODO(jackson): Block input unless content is interactive return new SlideTransition( - key: key, performance: performance, position: new AnimatedValue(_kTransitionStartPoint, end: Point.origin, curve: easeOut), child: new FadeTransition( @@ -293,5 +296,5 @@ class RouteState extends Route { super.didPop(result); } - Widget build(Key key, NavigatorState navigator) => null; + Widget build(NavigatorState navigator, WatchableAnimationPerformance nextRoutePerformance) => null; } diff --git a/packages/flutter/lib/src/widgets/popup_menu.dart b/packages/flutter/lib/src/widgets/popup_menu.dart index 60e02929d5..f66f1007c7 100644 --- a/packages/flutter/lib/src/widgets/popup_menu.dart +++ b/packages/flutter/lib/src/widgets/popup_menu.dart @@ -169,10 +169,10 @@ class MenuRoute extends Route { bool get ephemeral => false; // we could make this true, but then we'd have to use popRoute(), not pop(), in menus bool get modal => true; - - Duration get transitionDuration => _kMenuDuration; bool get opaque => false; - Widget build(Key key, NavigatorState navigator) { + Duration get transitionDuration => _kMenuDuration; + + Widget build(NavigatorState navigator, WatchableAnimationPerformance nextRoutePerformance) { return new Positioned( top: position?.top, right: position?.right, @@ -182,7 +182,6 @@ class MenuRoute extends Route { key: new GlobalObjectKey(this), autofocus: true, child: new PopupMenu( - key: key, items: builder != null ? builder(navigator) : const [], level: level, navigator: navigator,