From 1c06ea17a3498a331f1fcfa197e53c418a014bc6 Mon Sep 17 00:00:00 2001 From: Collin Jackson Date: Thu, 20 Aug 2015 14:58:49 -0700 Subject: [PATCH] Fix #721 Dialogs should appear in place rather than animating in from bottom --- packages/flutter/lib/widgets/dialog.dart | 44 +++++++++++++++ packages/flutter/lib/widgets/navigator.dart | 55 ++++++------------- packages/flutter/lib/widgets/transitions.dart | 2 + 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/packages/flutter/lib/widgets/dialog.dart b/packages/flutter/lib/widgets/dialog.dart index b73aa109c8..98e8840517 100644 --- a/packages/flutter/lib/widgets/dialog.dart +++ b/packages/flutter/lib/widgets/dialog.dart @@ -4,6 +4,8 @@ import 'dart:async'; +import 'package:sky/animation/animated_value.dart'; +import 'package:sky/animation/curves.dart'; import 'package:sky/theme/colors.dart' as colors; import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/default_text_style.dart'; @@ -12,6 +14,7 @@ import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/navigator.dart'; import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/theme.dart'; +import 'package:sky/widgets/transitions.dart'; typedef Widget DialogBuilder(Navigator navigator); @@ -107,6 +110,47 @@ class Dialog extends Component { } } +class DialogRoute extends RouteBase { + DialogRoute({ this.completer, this.builder }); + + final Completer completer; + final RouteBuilder builder; + + Widget build(Navigator navigator, RouteBase route) => builder(navigator, route); + bool get isOpaque => false; + + void popState([dynamic result]) { + completer.complete(result); + } + + TransitionBase buildTransition({ Key key }) => new DialogTransition(key: key); +} + +const Duration _kTransitionDuration = const Duration(milliseconds: 150); +class DialogTransition extends TransitionBase { + DialogTransition({ + Key key, + Widget child, + Direction direction, + Function onDismissed, + Function onCompleted + }): super(key: key, + child: child, + duration: _kTransitionDuration, + direction: direction, + onDismissed: onDismissed, + onCompleted: onCompleted); + + Widget buildWithChild(Widget child) { + return new FadeTransition( + performance: performance, + direction: direction, + opacity: new AnimatedValue(0.0, end: 1.0, curve: easeOut), + child: child + ); + } +} + Future showDialog(Navigator navigator, DialogBuilder builder) { Completer completer = new Completer(); navigator.push(new DialogRoute( diff --git a/packages/flutter/lib/widgets/navigator.dart b/packages/flutter/lib/widgets/navigator.dart index ee36b7cef5..7aeb41a4fc 100644 --- a/packages/flutter/lib/widgets/navigator.dart +++ b/packages/flutter/lib/widgets/navigator.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; - import 'package:sky/animation/animated_value.dart'; import 'package:sky/animation/animation_performance.dart'; import 'package:sky/animation/curves.dart'; @@ -17,6 +15,7 @@ abstract class RouteBase { Widget build(Navigator navigator, RouteBase route); bool get isOpaque; void popState([dynamic result]) { assert(result == null); } + TransitionBase buildTransition({ Key key }); } class Route extends RouteBase { @@ -27,20 +26,7 @@ class Route extends RouteBase { Widget build(Navigator navigator, RouteBase route) => builder(navigator, route); bool get isOpaque => true; -} - -class DialogRoute extends RouteBase { - DialogRoute({ this.completer, this.builder }); - - final Completer completer; - final RouteBuilder builder; - - Widget build(Navigator navigator, RouteBase route) => builder(navigator, route); - bool get isOpaque => false; - - void popState([dynamic result]) { - completer.complete(result); - } + TransitionBase buildTransition({ Key key }) => new SlideUpFadeTransition(key: key); } class RouteState extends RouteBase { @@ -58,32 +44,30 @@ class RouteState extends RouteBase { if (callback != null) callback(this); } + + TransitionBase buildTransition({ Key key }) { + // Custom state routes shouldn't be asked to construct a transition + assert(false); + return null; + } } // TODO(jackson): Refactor this into its own file -// and support multiple transition types const Duration _kTransitionDuration = const Duration(milliseconds: 150); const Point _kTransitionStartPoint = const Point(0.0, 75.0); -class Transition extends TransitionBase { - Transition({ +class SlideUpFadeTransition extends TransitionBase { + SlideUpFadeTransition({ Key key, Widget child, Direction direction, Function onDismissed, - Function onCompleted, - this.interactive + Function onCompleted }): super(key: key, child: child, duration: _kTransitionDuration, direction: direction, onDismissed: onDismissed, onCompleted: onCompleted); - bool interactive; - - void syncFields(Transition source) { - interactive = source.interactive; - super.syncFields(source); - } Widget buildWithChild(Widget child) { // TODO(jackson): Hit testing should ignore transform @@ -201,22 +185,19 @@ class Navigator extends StatefulComponent { } if (child == null) continue; - Transition transition = new Transition( - key: new Key.fromObjectIdentity(historyEntry), - child: child, - direction: (i <= state.historyIndex) ? Direction.forward : Direction.reverse, - interactive: (i == state.historyIndex), - onDismissed: () { + TransitionBase transition = historyEntry.route.buildTransition(key: new Key.fromObjectIdentity(historyEntry)) + ..child = child + ..direction = (i <= state.historyIndex) ? Direction.forward : Direction.reverse + ..onDismissed = () { setState(() { state.history.remove(historyEntry); }); - }, - onCompleted: () { + } + ..onCompleted = () { setState(() { historyEntry.fullyOpaque = historyEntry.route.isOpaque; }); - } - ); + }; visibleRoutes.add(transition); } return new Focus(child: new Stack(visibleRoutes)); diff --git a/packages/flutter/lib/widgets/transitions.dart b/packages/flutter/lib/widgets/transitions.dart index dbb2661dd3..39cf34bc3f 100644 --- a/packages/flutter/lib/widgets/transitions.dart +++ b/packages/flutter/lib/widgets/transitions.dart @@ -8,6 +8,8 @@ import 'package:sky/animation/animated_value.dart'; import 'package:sky/widgets/basic.dart'; import 'package:vector_math/vector_math.dart'; +export 'package:sky/animation/direction.dart' show Direction; + dynamic _maybe(AnimatedValue x) => x != null ? x.value : null; // A helper class to anchor widgets to one another. Pass an instance of this to