mirror of
https://github.com/flutter/flutter
synced 2024-10-14 04:02:56 +00:00
parent
01778c4895
commit
e73bbd949e
|
@ -251,13 +251,13 @@ class StockHome extends StatefulComponent {
|
|||
});
|
||||
}
|
||||
|
||||
Anchor _snackBarAnchor = new Anchor();
|
||||
GlobalKey snackBarKey = new GlobalKey(label: 'snackbar');
|
||||
Widget buildSnackBar() {
|
||||
if (_snackBarStatus == AnimationStatus.dismissed)
|
||||
return null;
|
||||
return new SnackBar(
|
||||
transitionKey: snackBarKey,
|
||||
showing: _isSnackBarShowing,
|
||||
anchor: _snackBarAnchor,
|
||||
content: new Text("Stock purchased!"),
|
||||
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
|
||||
onDismissed: () { setState(() { _snackBarStatus = AnimationStatus.dismissed; }); }
|
||||
|
@ -272,12 +272,14 @@ class StockHome extends StatefulComponent {
|
|||
}
|
||||
|
||||
Widget buildFloatingActionButton() {
|
||||
return _snackBarAnchor.build(
|
||||
new FloatingActionButton(
|
||||
return new TransitionProxy(
|
||||
transitionKey: snackBarKey,
|
||||
child: new FloatingActionButton(
|
||||
child: new Icon(type: 'content/add', size: 24),
|
||||
backgroundColor: Colors.redAccent[200],
|
||||
onPressed: _handleStockPurchased
|
||||
));
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void addMenuToOverlays(List<Widget> overlays) {
|
||||
|
|
|
@ -15,7 +15,7 @@ class Stocklist extends Component {
|
|||
child: new ScrollableList<Stock>(
|
||||
items: stocks,
|
||||
itemExtent: StockRow.kHeight,
|
||||
itemBuilder: (stock) => new StockRow(stock: stock)
|
||||
itemBuilder: (Stock stock) => new StockRow(stock: stock)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,21 +22,28 @@ class ProgressIndicatorApp extends App {
|
|||
reverseCurve: ease,
|
||||
interval: new Interval(0.0, 0.9)
|
||||
);
|
||||
valueAnimation.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.dismissed || status == AnimationStatus.completed)
|
||||
reverseValueAnimationDirection();
|
||||
});
|
||||
valueAnimation.play(valueAnimationDirection);
|
||||
}
|
||||
|
||||
void handleTap() {
|
||||
if (valueAnimation.isAnimating)
|
||||
valueAnimation.stop();
|
||||
else
|
||||
valueAnimation.resume();
|
||||
setState(() {
|
||||
// valueAnimation.isAnimating is part of our build state
|
||||
if (valueAnimation.isAnimating)
|
||||
valueAnimation.stop();
|
||||
else
|
||||
valueAnimation.resume();
|
||||
});
|
||||
}
|
||||
|
||||
void reverseValueAnimationDirection() {
|
||||
setState(() {
|
||||
valueAnimationDirection = (valueAnimationDirection == Direction.forward)
|
||||
? Direction.reverse
|
||||
: Direction.forward;
|
||||
});
|
||||
valueAnimationDirection = (valueAnimationDirection == Direction.forward)
|
||||
? Direction.reverse
|
||||
: Direction.forward;
|
||||
valueAnimation.play(valueAnimationDirection);
|
||||
}
|
||||
|
||||
Widget buildIndicators() {
|
||||
|
@ -58,11 +65,12 @@ class ProgressIndicatorApp extends App {
|
|||
width: 50.0,
|
||||
height: 30.0,
|
||||
child: new CircularProgressIndicator(value: valueAnimation.value)
|
||||
)
|
||||
),
|
||||
new Text("${(valueAnimation.value * 100.0).toStringAsFixed(1)}%" + (valueAnimation.isAnimating ? '' : ' (paused)'))
|
||||
];
|
||||
return new Column(
|
||||
indicators
|
||||
.map((c) => new Container(child: c, margin: const EdgeDims.symmetric(vertical: 20.0)))
|
||||
.map((c) => new Container(child: c, margin: const EdgeDims.symmetric(vertical: 15.0, horizontal: 20.0)))
|
||||
.toList(),
|
||||
justifyContent: FlexJustifyContent.center
|
||||
);
|
||||
|
@ -76,10 +84,7 @@ class ProgressIndicatorApp extends App {
|
|||
decoration: new BoxDecoration(backgroundColor: Theme.of(this).cardColor),
|
||||
child: new BuilderTransition(
|
||||
variables: [valueAnimation.variable],
|
||||
direction: valueAnimationDirection,
|
||||
performance: valueAnimation,
|
||||
onDismissed: reverseValueAnimationDirection,
|
||||
onCompleted: reverseValueAnimationDirection,
|
||||
performance: valueAnimation.view,
|
||||
builder: buildIndicators
|
||||
)
|
||||
)
|
||||
|
@ -94,10 +99,13 @@ class ProgressIndicatorApp extends App {
|
|||
accentColor: Colors.redAccent[200]
|
||||
),
|
||||
child: new Title(
|
||||
title: 'Cards',
|
||||
title: 'Progress Indicators',
|
||||
child: new Scaffold(
|
||||
toolbar: new ToolBar(center: new Text('Progress Indicators')),
|
||||
body: body
|
||||
body: new DefaultTextStyle(
|
||||
style: Theme.of(this).text.title,
|
||||
child: body
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -15,7 +15,10 @@ enum Direction {
|
|||
reverse
|
||||
}
|
||||
|
||||
/// A variable that changes as an animation progresses
|
||||
/// An interface describing a variable that changes as an animation progresses.
|
||||
///
|
||||
/// AnimatedVariables, by convention, must be cheap to create. This allows them to be used in
|
||||
/// build functions in Widgets.
|
||||
abstract class AnimatedVariable {
|
||||
/// Update the variable to a given time in an animation that is running in the given direction
|
||||
void setProgress(double t, Direction direction);
|
||||
|
|
|
@ -23,6 +23,26 @@ enum AnimationStatus {
|
|||
completed,
|
||||
}
|
||||
|
||||
typedef void AnimationPerformanceListener();
|
||||
typedef void AnimationPerformanceStatusListener(AnimationStatus status);
|
||||
|
||||
/// An interface that is implemented by [AnimationPerformance] that exposes a
|
||||
/// read-only view of the underlying performance. This is used by classes that
|
||||
/// want to watch a performance but should not be able to change the
|
||||
/// performance's state.
|
||||
abstract class WatchableAnimationPerformance {
|
||||
/// Update the given variable according to the current progress of the performance
|
||||
void updateVariable(AnimatedVariable variable);
|
||||
/// Calls the listener every time the progress of the performance changes
|
||||
void addListener(AnimationPerformanceListener listener);
|
||||
/// Stop calling the listener every time the progress of the performance changes
|
||||
void removeListener(AnimationPerformanceListener listener);
|
||||
/// Calls listener every time the status of the performance changes
|
||||
void addStatusListener(AnimationPerformanceStatusListener listener);
|
||||
/// Stops calling the listener every time the status of the performance changes
|
||||
void removeStatusListener(AnimationPerformanceStatusListener listener);
|
||||
}
|
||||
|
||||
/// A collection of values that animated based on a timeline
|
||||
///
|
||||
/// For example, a performance may handle an animation of a menu opening by
|
||||
|
@ -31,12 +51,17 @@ enum AnimationStatus {
|
|||
/// may also take direct control of the timeline by manipulating [progress], or
|
||||
/// [fling] the timeline causing a physics-based simulation to take over the
|
||||
/// progression.
|
||||
class AnimationPerformance {
|
||||
class AnimationPerformance implements WatchableAnimationPerformance {
|
||||
AnimationPerformance({ AnimatedVariable variable, this.duration }) :
|
||||
_variable = variable {
|
||||
_timeline = new Timeline(_tick);
|
||||
}
|
||||
|
||||
/// Returns a [WatchableAnimationPerformance] for this performance,
|
||||
/// so that a pointer to this object can be passed around without
|
||||
/// allowing users of that pointer to mutate the AnimationPerformance state.
|
||||
WatchableAnimationPerformance get view => this;
|
||||
|
||||
/// The length of time this performance should last
|
||||
Duration duration;
|
||||
|
||||
|
@ -155,33 +180,33 @@ class AnimationPerformance {
|
|||
return _timeline.fling(force.release(progress, velocity));
|
||||
}
|
||||
|
||||
final List<Function> _listeners = new List<Function>();
|
||||
final List<AnimationPerformanceListener> _listeners = new List<AnimationPerformanceListener>();
|
||||
|
||||
/// Calls the listener every time the progress of this performance changes
|
||||
void addListener(Function listener) {
|
||||
void addListener(AnimationPerformanceListener listener) {
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
/// Stop calling the listener every time the progress of this performance changes
|
||||
void removeListener(Function listener) {
|
||||
void removeListener(AnimationPerformanceListener listener) {
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
void _notifyListeners() {
|
||||
List<Function> localListeners = new List<Function>.from(_listeners);
|
||||
for (Function listener in localListeners)
|
||||
List<AnimationPerformanceListener> localListeners = new List<AnimationPerformanceListener>.from(_listeners);
|
||||
for (AnimationPerformanceListener listener in localListeners)
|
||||
listener();
|
||||
}
|
||||
|
||||
final List<Function> _statusListeners = new List<Function>();
|
||||
final List<AnimationPerformanceStatusListener> _statusListeners = new List<AnimationPerformanceStatusListener>();
|
||||
|
||||
/// Calls listener every time the status of this performance changes
|
||||
void addStatusListener(Function listener) {
|
||||
void addStatusListener(AnimationPerformanceStatusListener listener) {
|
||||
_statusListeners.add(listener);
|
||||
}
|
||||
|
||||
/// Stops calling the listener every time the status of this performance changes
|
||||
void removeStatusListener(Function listener) {
|
||||
void removeStatusListener(AnimationPerformanceStatusListener listener) {
|
||||
_statusListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
@ -189,8 +214,8 @@ class AnimationPerformance {
|
|||
void _checkStatusChanged() {
|
||||
AnimationStatus currentStatus = status;
|
||||
if (currentStatus != _lastStatus) {
|
||||
List<Function> localListeners = new List<Function>.from(_statusListeners);
|
||||
for (Function listener in localListeners)
|
||||
List<AnimationPerformanceStatusListener> localListeners = new List<AnimationPerformanceStatusListener>.from(_statusListeners);
|
||||
for (AnimationPerformanceStatusListener listener in localListeners)
|
||||
listener(currentStatus);
|
||||
}
|
||||
_lastStatus = currentStatus;
|
||||
|
|
|
@ -7,47 +7,49 @@ import 'package:sky/src/widgets/framework.dart';
|
|||
|
||||
abstract class AnimatedComponent extends StatefulComponent {
|
||||
|
||||
AnimatedComponent({ Key key }) : super(key: key);
|
||||
AnimatedComponent({ Key key, this.direction, this.duration }) : super(key: key);
|
||||
|
||||
void syncConstructorArguments(AnimatedComponent source) { }
|
||||
Duration duration;
|
||||
Direction direction;
|
||||
|
||||
final List<AnimationPerformance> _watchedPerformances = new List<AnimationPerformance>();
|
||||
void syncConstructorArguments(AnimatedComponent source) {
|
||||
bool resumePerformance = false;
|
||||
if (duration != source.duration) {
|
||||
duration = source.duration;
|
||||
resumePerformance = true;
|
||||
}
|
||||
if (direction != source.direction) {
|
||||
direction = source.direction;
|
||||
resumePerformance = true;
|
||||
}
|
||||
if (resumePerformance)
|
||||
performance.play(direction);
|
||||
}
|
||||
|
||||
void _performanceChanged() {
|
||||
setState(() {
|
||||
// We don't actually have any state to change, per se,
|
||||
// we just know that we have in fact changed state.
|
||||
AnimationPerformance get performance => _performance;
|
||||
AnimationPerformance _performance;
|
||||
|
||||
void initState() {
|
||||
_performance = new AnimationPerformance(duration: duration);
|
||||
performance.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.completed)
|
||||
handleCompleted();
|
||||
else if (status == AnimationStatus.dismissed)
|
||||
handleDismissed();
|
||||
});
|
||||
if (buildDependsOnPerformance) {
|
||||
performance.addListener(() {
|
||||
setState(() {
|
||||
// We don't actually have any state to change, per se,
|
||||
// we just know that we have in fact changed state.
|
||||
});
|
||||
});
|
||||
}
|
||||
performance.play(direction);
|
||||
}
|
||||
|
||||
bool isWatching(AnimationPerformance performance) {
|
||||
return _watchedPerformances.contains(performance);
|
||||
}
|
||||
|
||||
void watch(AnimationPerformance performance) {
|
||||
assert(!isWatching(performance));
|
||||
_watchedPerformances.add(performance);
|
||||
if (mounted)
|
||||
performance.addListener(_performanceChanged);
|
||||
}
|
||||
|
||||
void unwatch(AnimationPerformance performance) {
|
||||
assert(isWatching(performance));
|
||||
_watchedPerformances.remove(performance);
|
||||
if (mounted)
|
||||
performance.removeListener(_performanceChanged);
|
||||
}
|
||||
|
||||
void didMount() {
|
||||
for (AnimationPerformance performance in _watchedPerformances)
|
||||
performance.addListener(_performanceChanged);
|
||||
super.didMount();
|
||||
}
|
||||
|
||||
void didUnmount() {
|
||||
for (AnimationPerformance performance in _watchedPerformances)
|
||||
performance.removeListener(_performanceChanged);
|
||||
super.didUnmount();
|
||||
}
|
||||
bool get buildDependsOnPerformance => false;
|
||||
void handleCompleted() { }
|
||||
void handleDismissed() { }
|
||||
|
||||
}
|
||||
|
|
|
@ -131,6 +131,8 @@ class Dialog extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
const Duration _kTransitionDuration = const Duration(milliseconds: 150);
|
||||
|
||||
class DialogRoute extends RouteBase {
|
||||
DialogRoute({ this.completer, this.builder });
|
||||
|
||||
|
@ -144,28 +146,10 @@ class DialogRoute extends RouteBase {
|
|||
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) {
|
||||
Duration get transitionDuration => _kTransitionDuration;
|
||||
TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance }) {
|
||||
return new FadeTransition(
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: easeOut),
|
||||
child: child
|
||||
);
|
||||
|
|
|
@ -54,6 +54,10 @@ class Dismissable extends StatefulComponent {
|
|||
|
||||
void initState() {
|
||||
_fadePerformance = new AnimationPerformance(duration: _kCardDismissFadeout);
|
||||
_fadePerformance.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.completed)
|
||||
_handleFadeCompleted();
|
||||
});
|
||||
}
|
||||
|
||||
void syncConstructorArguments(Dismissable source) {
|
||||
|
@ -99,6 +103,7 @@ class Dismissable extends StatefulComponent {
|
|||
_resizePerformance = new AnimationPerformance()
|
||||
..duration = _kCardDismissResize
|
||||
..addListener(_handleResizeProgressChanged);
|
||||
_resizePerformance.play();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -226,8 +231,7 @@ class Dismissable extends StatefulComponent {
|
|||
);
|
||||
|
||||
return new SquashTransition(
|
||||
performance: _resizePerformance,
|
||||
direction: Direction.forward,
|
||||
performance: _resizePerformance.view,
|
||||
width: _directionIsYAxis ? squashAxisExtent : null,
|
||||
height: !_directionIsYAxis ? squashAxisExtent : null
|
||||
);
|
||||
|
@ -243,11 +247,10 @@ class Dismissable extends StatefulComponent {
|
|||
child: new SizeObserver(
|
||||
callback: _handleSizeChanged,
|
||||
child: new FadeTransition(
|
||||
performance: _fadePerformance,
|
||||
onCompleted: _handleFadeCompleted,
|
||||
performance: _fadePerformance.view,
|
||||
opacity: new AnimatedValue<double>(1.0, end: 0.0),
|
||||
child: new SlideTransition(
|
||||
performance: _fadePerformance,
|
||||
performance: _fadePerformance.view,
|
||||
position: new AnimatedValue<Point>(Point.origin, end: _activeCardDragEndPoint),
|
||||
child: child
|
||||
)
|
||||
|
|
|
@ -58,32 +58,41 @@ class Drawer extends StatefulComponent {
|
|||
|
||||
void initState() {
|
||||
_performance = new AnimationPerformance(duration: _kBaseSettleDuration);
|
||||
|
||||
_performance.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.dismissed)
|
||||
_handleDismissed();
|
||||
});
|
||||
// Use a spring force for animating the drawer. We can't use curves for
|
||||
// this because we need a linear curve in order to track the user's finger
|
||||
// while dragging.
|
||||
_performance.attachedForce = kDefaultSpringForce;
|
||||
|
||||
if (navigator != null) {
|
||||
// TODO(ianh): This is crazy. We should convert drawer to use a pattern like openDialog().
|
||||
// https://github.com/domokit/sky_engine/pull/1186
|
||||
scheduleMicrotask(() {
|
||||
navigator.pushState(this, (_) => _performance.reverse());
|
||||
});
|
||||
}
|
||||
_performance.play(_direction);
|
||||
}
|
||||
|
||||
Direction get _direction => showing ? Direction.forward : Direction.reverse;
|
||||
|
||||
void syncConstructorArguments(Drawer source) {
|
||||
children = source.children;
|
||||
if (showing != source.showing) {
|
||||
showing = source.showing;
|
||||
_performance.play(_direction);
|
||||
}
|
||||
level = source.level;
|
||||
navigator = source.navigator;
|
||||
showing = source.showing;
|
||||
onDismissed = source.onDismissed;
|
||||
navigator = source.navigator;
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
var mask = new GestureDetector(
|
||||
child: new ColorTransition(
|
||||
performance: _performance,
|
||||
direction: showing ? Direction.forward : Direction.reverse,
|
||||
performance: _performance.view,
|
||||
color: new AnimatedColorValue(Colors.transparent, end: const Color(0x7F000000)),
|
||||
child: new Container()
|
||||
),
|
||||
|
@ -93,10 +102,8 @@ class Drawer extends StatefulComponent {
|
|||
);
|
||||
|
||||
Widget content = new SlideTransition(
|
||||
performance: _performance,
|
||||
direction: showing ? Direction.forward : Direction.reverse,
|
||||
performance: _performance.view,
|
||||
position: new AnimatedValue<Point>(_kClosedPosition, end: _kOpenPosition),
|
||||
onDismissed: _onDismissed,
|
||||
child: new AnimatedContainer(
|
||||
behavior: implicitlyAnimate(const Duration(milliseconds: 200)),
|
||||
decoration: new BoxDecoration(
|
||||
|
@ -115,7 +122,7 @@ class Drawer extends StatefulComponent {
|
|||
);
|
||||
}
|
||||
|
||||
void _onDismissed() {
|
||||
void _handleDismissed() {
|
||||
if (navigator != null &&
|
||||
navigator.currentRoute is RouteState &&
|
||||
(navigator.currentRoute as RouteState).owner == this) // TODO(ianh): remove cast once analyzer is cleverer
|
||||
|
|
|
@ -13,12 +13,14 @@ abstract class GlobalKeyWatcher extends StatefulComponent {
|
|||
GlobalKey watchedKey;
|
||||
|
||||
void syncConstructorArguments(GlobalKeyWatcher source) {
|
||||
if (source != source.watchedKey) {
|
||||
_removeListeners();
|
||||
if (watchedKey != source.watchedKey) {
|
||||
if (watchedKey != null)
|
||||
_removeListeners();
|
||||
watchedKey = source.watchedKey;
|
||||
if (mounted)
|
||||
if (mounted && watchedKey != null) {
|
||||
_setWatchedWidget(GlobalKey.getWidget(watchedKey));
|
||||
_addListeners();
|
||||
_addListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +31,7 @@ abstract class GlobalKeyWatcher extends StatefulComponent {
|
|||
if (watchedWidget != value) {
|
||||
if (watchedWidget != null)
|
||||
stopWatching();
|
||||
assert(debugValidateWatchedWidget(value));
|
||||
assert(value == null || debugValidateWatchedWidget(value));
|
||||
setState(() {
|
||||
_watchedWidget = value;
|
||||
});
|
||||
|
@ -42,13 +44,16 @@ abstract class GlobalKeyWatcher extends StatefulComponent {
|
|||
|
||||
void didMount() {
|
||||
super.didMount();
|
||||
_setWatchedWidget(GlobalKey.getWidget(watchedKey));
|
||||
_addListeners();
|
||||
if (watchedKey != null) {
|
||||
_setWatchedWidget(GlobalKey.getWidget(watchedKey));
|
||||
_addListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void didUnmount() {
|
||||
super.didUnmount();
|
||||
_removeListeners();
|
||||
if (watchedKey != null)
|
||||
_removeListeners();
|
||||
_setWatchedWidget(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,49 @@ import 'package:sky/src/widgets/transitions.dart';
|
|||
|
||||
typedef Widget RouteBuilder(Navigator navigator, RouteBase route);
|
||||
|
||||
typedef void NotificationCallback();
|
||||
|
||||
abstract class RouteBase {
|
||||
Widget build(Navigator navigator, RouteBase route);
|
||||
bool get isOpaque;
|
||||
void popState([dynamic result]) { assert(result == null); }
|
||||
TransitionBase buildTransition({ Key key });
|
||||
|
||||
AnimationPerformance _performance;
|
||||
NotificationCallback onDismissed;
|
||||
NotificationCallback onCompleted;
|
||||
WatchableAnimationPerformance ensurePerformance({ Direction direction }) {
|
||||
assert(direction != null);
|
||||
if (_performance == null) {
|
||||
_performance = new AnimationPerformance(duration: transitionDuration);
|
||||
_performance.addStatusListener((AnimationStatus status) {
|
||||
switch (status) {
|
||||
case AnimationStatus.dismissed:
|
||||
if (onDismissed != null)
|
||||
onDismissed();
|
||||
break;
|
||||
case AnimationStatus.completed:
|
||||
if (onCompleted != null)
|
||||
onCompleted();
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
});
|
||||
}
|
||||
AnimationStatus desiredStatus = direction == Direction.forward ? AnimationStatus.forward : AnimationStatus.reverse;
|
||||
if (_performance.status != desiredStatus)
|
||||
_performance.play(direction);
|
||||
return _performance.view;
|
||||
}
|
||||
|
||||
Duration get transitionDuration;
|
||||
TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance });
|
||||
|
||||
String toString() => '$runtimeType()';
|
||||
}
|
||||
|
||||
const Duration _kTransitionDuration = const Duration(milliseconds: 150);
|
||||
const Point _kTransitionStartPoint = const Point(0.0, 75.0);
|
||||
class Route extends RouteBase {
|
||||
Route({ this.name, this.builder });
|
||||
|
||||
|
@ -25,7 +61,24 @@ class Route extends RouteBase {
|
|||
|
||||
Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
|
||||
bool get isOpaque => true;
|
||||
TransitionBase buildTransition({ Key key }) => new SlideUpFadeTransition(key: key);
|
||||
|
||||
Duration get transitionDuration => _kTransitionDuration;
|
||||
TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance }) {
|
||||
// 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<Point>(_kTransitionStartPoint, end: Point.origin, curve: easeOut),
|
||||
child: new FadeTransition(
|
||||
performance: performance,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: easeOut),
|
||||
child: child
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
String toString() => '$runtimeType(name="$name")';
|
||||
}
|
||||
|
||||
class RouteState extends RouteBase {
|
||||
|
@ -44,52 +97,23 @@ class RouteState extends RouteBase {
|
|||
callback(this);
|
||||
}
|
||||
|
||||
TransitionBase buildTransition({ Key key }) {
|
||||
// Custom state routes shouldn't be asked to construct a transition
|
||||
// Custom state routes shouldn't be asked to construct a transition
|
||||
Duration get transitionDuration {
|
||||
assert(false);
|
||||
return const Duration();
|
||||
}
|
||||
TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance }) {
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jackson): Refactor this into its own file
|
||||
const Duration _kTransitionDuration = const Duration(milliseconds: 150);
|
||||
const Point _kTransitionStartPoint = const Point(0.0, 75.0);
|
||||
class SlideUpFadeTransition extends TransitionBase {
|
||||
SlideUpFadeTransition({
|
||||
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) {
|
||||
// TODO(jackson): Hit testing should ignore transform
|
||||
// TODO(jackson): Block input unless content is interactive
|
||||
return new SlideTransition(
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
position: new AnimatedValue<Point>(_kTransitionStartPoint, end: Point.origin, curve: easeOut),
|
||||
child: new FadeTransition(
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: easeOut),
|
||||
child: child
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HistoryEntry {
|
||||
HistoryEntry({ this.route });
|
||||
final RouteBase route;
|
||||
bool fullyOpaque = false;
|
||||
// TODO(jackson): Keep track of the requested transition
|
||||
String toString() => "HistoryEntry($route, hashCode=$hashCode)";
|
||||
}
|
||||
|
||||
class NavigationState {
|
||||
|
@ -116,6 +140,7 @@ class NavigationState {
|
|||
}
|
||||
|
||||
void push(RouteBase route) {
|
||||
assert(!_debugCurrentlyHaveRoute(route));
|
||||
HistoryEntry historyEntry = new HistoryEntry(route: route);
|
||||
history.insert(historyIndex + 1, historyEntry);
|
||||
historyIndex++;
|
||||
|
@ -129,6 +154,10 @@ class NavigationState {
|
|||
historyIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
bool _debugCurrentlyHaveRoute(RouteBase route) {
|
||||
return history.any((entry) => entry.route == route);
|
||||
}
|
||||
}
|
||||
|
||||
class Navigator extends StatefulComponent {
|
||||
|
@ -184,19 +213,25 @@ class Navigator extends StatefulComponent {
|
|||
}
|
||||
if (child == null)
|
||||
continue;
|
||||
TransitionBase transition = historyEntry.route.buildTransition(key: new ObjectKey(historyEntry))
|
||||
..child = child
|
||||
..direction = (i <= state.historyIndex) ? Direction.forward : Direction.reverse
|
||||
..onDismissed = () {
|
||||
setState(() {
|
||||
state.history.remove(historyEntry);
|
||||
});
|
||||
}
|
||||
..onCompleted = () {
|
||||
setState(() {
|
||||
historyEntry.fullyOpaque = historyEntry.route.isOpaque;
|
||||
});
|
||||
};
|
||||
WatchableAnimationPerformance performance = historyEntry.route.ensurePerformance(
|
||||
direction: (i <= state.historyIndex) ? Direction.forward : Direction.reverse
|
||||
);
|
||||
historyEntry.route.onDismissed = () {
|
||||
setState(() {
|
||||
assert(state.history.contains(historyEntry));
|
||||
state.history.remove(historyEntry);
|
||||
});
|
||||
};
|
||||
historyEntry.route.onCompleted = () {
|
||||
setState(() {
|
||||
historyEntry.fullyOpaque = historyEntry.route.isOpaque;
|
||||
});
|
||||
};
|
||||
TransitionBase transition = historyEntry.route.buildTransition(
|
||||
key: new ObjectKey(historyEntry),
|
||||
child: child,
|
||||
performance: performance
|
||||
);
|
||||
visibleRoutes.add(transition);
|
||||
}
|
||||
return new Focus(child: new Stack(visibleRoutes));
|
||||
|
|
|
@ -45,10 +45,13 @@ class PopupMenu extends StatefulComponent {
|
|||
AnimationPerformance _performance;
|
||||
|
||||
void initState() {
|
||||
_performance = new AnimationPerformance()
|
||||
..duration = _kMenuDuration;
|
||||
_performance = new AnimationPerformance(duration: _kMenuDuration);
|
||||
_performance.timing = new AnimationTiming()
|
||||
..reverseInterval = new Interval(0.0, _kMenuCloseIntervalEnd);
|
||||
..reverseInterval = new Interval(0.0, _kMenuCloseIntervalEnd);
|
||||
_performance.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.dismissed)
|
||||
_handleDismissed();
|
||||
});
|
||||
_updateBoxPainter();
|
||||
|
||||
if (showing)
|
||||
|
@ -69,6 +72,7 @@ class PopupMenu extends StatefulComponent {
|
|||
|
||||
void _open() {
|
||||
navigator.pushState(this, (_) => _close());
|
||||
_performance.play();
|
||||
}
|
||||
|
||||
void _close() {
|
||||
|
@ -82,7 +86,7 @@ class PopupMenu extends StatefulComponent {
|
|||
boxShadow: shadows[level]));
|
||||
}
|
||||
|
||||
void _onDismissed() {
|
||||
void _handleDismissed() {
|
||||
if (navigator != null &&
|
||||
navigator.currentRoute is RouteState &&
|
||||
(navigator.currentRoute as RouteState).owner == this) // TODO(ianh): remove cast once analyzer is cleverer
|
||||
|
@ -100,24 +104,21 @@ class PopupMenu extends StatefulComponent {
|
|||
double start = (i + 1) * unit;
|
||||
double end = (start + 1.5 * unit).clamp(0.0, 1.0);
|
||||
children.add(new FadeTransition(
|
||||
direction: showing ? Direction.forward : Direction.reverse,
|
||||
performance: _performance,
|
||||
performance: _performance.view,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(start, end)),
|
||||
child: items[i]));
|
||||
child: items[i])
|
||||
);
|
||||
}
|
||||
|
||||
final width = new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, unit));
|
||||
final height = new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, unit * items.length));
|
||||
return new FadeTransition(
|
||||
direction: showing ? Direction.forward : Direction.reverse,
|
||||
performance: _performance,
|
||||
onDismissed: _onDismissed,
|
||||
performance: _performance.view,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, 1.0 / 3.0)),
|
||||
child: new Container(
|
||||
margin: new EdgeDims.all(_kMenuMargin),
|
||||
child: new BuilderTransition(
|
||||
direction: showing ? Direction.forward : Direction.reverse,
|
||||
performance: _performance,
|
||||
performance: _performance.view,
|
||||
variables: [width, height],
|
||||
builder: () {
|
||||
return new CustomPaint(
|
||||
|
|
|
@ -25,16 +25,21 @@ abstract class ProgressIndicator extends StatefulComponent {
|
|||
double value; // Null for non-determinate progress indicator.
|
||||
double bufferValue; // TODO(hansmuller) implement the support for this.
|
||||
|
||||
AnimationPerformance _animation;
|
||||
double get _animationValue => (_animation.variable as AnimatedValue<double>).value;
|
||||
AnimationPerformance _performance;
|
||||
double get _performanceValue => (_performance.variable as AnimatedValue<double>).value;
|
||||
Color get _backgroundColor => Theme.of(this).primarySwatch[200];
|
||||
Color get _valueColor => Theme.of(this).primaryColor;
|
||||
Object get _customPaintToken => value != null ? value : _animationValue;
|
||||
Object get _customPaintToken => value != null ? value : _performanceValue;
|
||||
|
||||
void initState() {
|
||||
_animation = new AnimationPerformance()
|
||||
_performance = new AnimationPerformance()
|
||||
..duration = const Duration(milliseconds: 1500)
|
||||
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease);
|
||||
_performance.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.completed)
|
||||
_restartAnimation();
|
||||
});
|
||||
_performance.play();
|
||||
}
|
||||
|
||||
void syncConstructorArguments(ProgressIndicator source) {
|
||||
|
@ -43,8 +48,8 @@ abstract class ProgressIndicator extends StatefulComponent {
|
|||
}
|
||||
|
||||
void _restartAnimation() {
|
||||
_animation.progress = 0.0;
|
||||
_animation.play();
|
||||
_performance.progress = 0.0;
|
||||
_performance.play();
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
|
@ -52,10 +57,8 @@ abstract class ProgressIndicator extends StatefulComponent {
|
|||
return _buildIndicator();
|
||||
|
||||
return new BuilderTransition(
|
||||
variables: [_animation.variable],
|
||||
direction: Direction.forward,
|
||||
performance: _animation,
|
||||
onCompleted: _restartAnimation,
|
||||
variables: [_performance.variable],
|
||||
performance: _performance.view,
|
||||
builder: _buildIndicator
|
||||
);
|
||||
}
|
||||
|
@ -81,7 +84,7 @@ class LinearProgressIndicator extends ProgressIndicator {
|
|||
double width = value.clamp(0.0, 1.0) * size.width;
|
||||
canvas.drawRect(Point.origin & new Size(width, size.height), paint);
|
||||
} else {
|
||||
double startX = size.width * (1.5 * _animationValue - 0.5);
|
||||
double startX = size.width * (1.5 * _performanceValue - 0.5);
|
||||
double endX = startX + 0.5 * size.width;
|
||||
double x = startX.clamp(0.0, size.width);
|
||||
double width = endX.clamp(0.0, size.width) - x;
|
||||
|
@ -125,7 +128,7 @@ class CircularProgressIndicator extends ProgressIndicator {
|
|||
..arcTo(Point.origin & size, _kStartAngle, angle, false);
|
||||
canvas.drawPath(path, paint);
|
||||
} else {
|
||||
double startAngle = _kTwoPI * (1.75 * _animationValue - 0.75);
|
||||
double startAngle = _kTwoPI * (1.75 * _performanceValue - 0.75);
|
||||
double endAngle = startAngle + _kTwoPI * 0.75;
|
||||
double arcAngle = startAngle.clamp(0.0, _kTwoPI);
|
||||
double arcSweep = endAngle.clamp(0.0, _kTwoPI) - arcAngle;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import 'package:sky/animation.dart';
|
||||
import 'package:sky/painting.dart';
|
||||
import 'package:sky/material.dart';
|
||||
import 'package:sky/src/widgets/animated_component.dart';
|
||||
import 'package:sky/src/widgets/basic.dart';
|
||||
import 'package:sky/src/widgets/default_text_style.dart';
|
||||
import 'package:sky/src/widgets/framework.dart';
|
||||
|
@ -17,6 +18,7 @@ import 'package:sky/src/widgets/transitions.dart';
|
|||
typedef void SnackBarDismissedCallback();
|
||||
|
||||
const Duration _kSlideInDuration = const Duration(milliseconds: 200);
|
||||
// TODO(ianh): factor out some of the constants below
|
||||
|
||||
class SnackBarAction extends Component {
|
||||
SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
|
||||
|
@ -38,25 +40,37 @@ class SnackBarAction extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
class SnackBar extends Component {
|
||||
class SnackBar extends AnimatedComponent {
|
||||
|
||||
SnackBar({
|
||||
Key key,
|
||||
this.anchor,
|
||||
this.transitionKey,
|
||||
this.content,
|
||||
this.actions,
|
||||
this.showing,
|
||||
bool showing,
|
||||
this.onDismissed
|
||||
}) : super(key: key) {
|
||||
}) : super(key: key, direction: showing ? Direction.forward : Direction.reverse, duration: _kSlideInDuration) {
|
||||
assert(content != null);
|
||||
}
|
||||
|
||||
Anchor anchor;
|
||||
Key transitionKey;
|
||||
Widget content;
|
||||
List<SnackBarAction> actions;
|
||||
bool showing;
|
||||
SnackBarDismissedCallback onDismissed;
|
||||
|
||||
void syncConstructorArguments(SnackBar source) {
|
||||
transitionKey = source.transitionKey;
|
||||
content = source.content;
|
||||
actions = source.actions;
|
||||
onDismissed = source.onDismissed;
|
||||
super.syncConstructorArguments(source);
|
||||
}
|
||||
|
||||
void handleDismissed() {
|
||||
if (onDismissed != null)
|
||||
onDismissed();
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
List<Widget> children = [
|
||||
new Flexible(
|
||||
|
@ -71,15 +85,15 @@ class SnackBar extends Component {
|
|||
];
|
||||
if (actions != null)
|
||||
children.addAll(actions);
|
||||
|
||||
return new SlideTransition(
|
||||
duration: _kSlideInDuration,
|
||||
direction: showing ? Direction.forward : Direction.reverse,
|
||||
position: new AnimatedValue<Point>(Point.origin,
|
||||
end: const Point(0.0, -52.0),
|
||||
curve: easeIn, reverseCurve: easeOut),
|
||||
onDismissed: onDismissed,
|
||||
anchor: anchor,
|
||||
key: transitionKey,
|
||||
performance: performance.view,
|
||||
position: new AnimatedValue<Point>(
|
||||
Point.origin,
|
||||
end: const Point(0.0, -52.0),
|
||||
curve: easeIn,
|
||||
reverseCurve: easeOut
|
||||
),
|
||||
child: new Material(
|
||||
level: 2,
|
||||
color: const Color(0xFF323232),
|
||||
|
|
|
@ -542,8 +542,7 @@ class TabBar extends Scrollable {
|
|||
style: textStyle,
|
||||
child: new BuilderTransition(
|
||||
variables: [_indicatorRect],
|
||||
direction: Direction.forward,
|
||||
performance: _indicatorAnimation,
|
||||
performance: _indicatorAnimation.view,
|
||||
builder: () {
|
||||
return new TabBarWrapper(
|
||||
children: tabs,
|
||||
|
|
|
@ -6,144 +6,125 @@ import 'package:sky/animation.dart';
|
|||
import 'package:sky/src/widgets/animated_component.dart';
|
||||
import 'package:sky/src/widgets/basic.dart';
|
||||
import 'package:sky/src/widgets/framework.dart';
|
||||
import 'package:sky/src/widgets/global_key_watcher.dart';
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
|
||||
export 'package:sky/animation.dart' show Direction;
|
||||
|
||||
// A helper class to anchor widgets to one another. Pass an instance of this to
|
||||
// a Transition, then use the build() method to create a child with the same
|
||||
// transition applied.
|
||||
class Anchor {
|
||||
Anchor();
|
||||
class TransitionProxy extends GlobalKeyWatcher {
|
||||
|
||||
TransitionBase transition;
|
||||
|
||||
Widget build(Widget child) {
|
||||
return new _AnchorTransition(anchoredTo: this, child: child);
|
||||
}
|
||||
}
|
||||
|
||||
// Used with the Anchor class to apply a transition to multiple children.
|
||||
class _AnchorTransition extends AnimatedComponent {
|
||||
_AnchorTransition({
|
||||
TransitionProxy({
|
||||
Key key,
|
||||
this.anchoredTo,
|
||||
GlobalKey transitionKey,
|
||||
this.child
|
||||
}) : super(key: key);
|
||||
}) : super(key: key, watchedKey: transitionKey);
|
||||
|
||||
Anchor anchoredTo;
|
||||
Widget child;
|
||||
TransitionBase get transition => anchoredTo.transition;
|
||||
|
||||
void initState() {
|
||||
if (transition != null)
|
||||
watch(transition.performance);
|
||||
}
|
||||
|
||||
void syncConstructorArguments(_AnchorTransition source) {
|
||||
if (transition != null && isWatching(transition.performance))
|
||||
unwatch(transition.performance);
|
||||
anchoredTo = source.anchoredTo;
|
||||
if (transition != null)
|
||||
watch(transition.performance);
|
||||
void syncConstructorArguments(TransitionProxy source) {
|
||||
child = source.child;
|
||||
super.syncConstructorArguments(source);
|
||||
}
|
||||
|
||||
bool debugValidateWatchedWidget(Widget candidate) {
|
||||
return candidate is TransitionBaseWithChild;
|
||||
}
|
||||
|
||||
TransitionBaseWithChild get transition => this.watchedWidget;
|
||||
|
||||
void startWatching() {
|
||||
transition.performance.addListener(_performanceChanged);
|
||||
}
|
||||
|
||||
void stopWatching() {
|
||||
transition.performance.removeListener(_performanceChanged);
|
||||
}
|
||||
|
||||
void _performanceChanged() {
|
||||
setState(() {
|
||||
// The performance changed, so we probably need to ask the transition
|
||||
// we're watching for a rebuild.
|
||||
});
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
if (transition == null)
|
||||
return child;
|
||||
return transition.buildWithChild(child);
|
||||
if (transition != null)
|
||||
return transition.buildWithChild(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class TransitionBase extends AnimatedComponent {
|
||||
abstract class TransitionBase extends StatefulComponent {
|
||||
|
||||
TransitionBase({
|
||||
Key key,
|
||||
this.child,
|
||||
this.anchor,
|
||||
this.direction,
|
||||
this.duration,
|
||||
this.performance,
|
||||
this.onDismissed,
|
||||
this.onCompleted
|
||||
}) : super(key: key);
|
||||
|
||||
Widget child;
|
||||
Anchor anchor;
|
||||
Direction direction;
|
||||
Duration duration;
|
||||
AnimationPerformance performance;
|
||||
Function onDismissed;
|
||||
Function onCompleted;
|
||||
|
||||
void initState() {
|
||||
if (anchor != null)
|
||||
anchor.transition = this;
|
||||
|
||||
if (performance == null) {
|
||||
assert(duration != null);
|
||||
performance = new AnimationPerformance(duration: duration);
|
||||
if (direction == Direction.reverse)
|
||||
performance.progress = 1.0;
|
||||
}
|
||||
performance.addStatusListener(_checkStatusChanged);
|
||||
|
||||
watch(performance);
|
||||
_start();
|
||||
this.performance
|
||||
}) : super(key: key) {
|
||||
assert(performance != null);
|
||||
}
|
||||
|
||||
WatchableAnimationPerformance performance;
|
||||
|
||||
void syncConstructorArguments(TransitionBase source) {
|
||||
if (performance != source.performance) {
|
||||
if (mounted)
|
||||
performance.removeListener(_performanceChanged);
|
||||
performance = source.performance;
|
||||
if (mounted)
|
||||
performance.addListener(_performanceChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void _performanceChanged() {
|
||||
setState(() {
|
||||
// The performance's state is our build state, and it changed already.
|
||||
});
|
||||
}
|
||||
|
||||
void didMount() {
|
||||
performance.addListener(_performanceChanged);
|
||||
super.didMount();
|
||||
}
|
||||
|
||||
void didUnmount() {
|
||||
performance.removeListener(_performanceChanged);
|
||||
super.didUnmount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class TransitionBaseWithChild extends TransitionBase {
|
||||
|
||||
TransitionBaseWithChild({
|
||||
Key key,
|
||||
this.child,
|
||||
WatchableAnimationPerformance performance
|
||||
}) : super(key: key, performance: performance);
|
||||
|
||||
Widget child;
|
||||
|
||||
void syncConstructorArguments(TransitionBaseWithChild source) {
|
||||
child = source.child;
|
||||
onCompleted = source.onCompleted;
|
||||
onDismissed = source.onDismissed;
|
||||
duration = source.duration;
|
||||
if (direction != source.direction) {
|
||||
direction = source.direction;
|
||||
_start();
|
||||
}
|
||||
super.syncConstructorArguments(source);
|
||||
}
|
||||
|
||||
void _start() {
|
||||
performance.play(direction);
|
||||
}
|
||||
|
||||
void _checkStatusChanged(AnimationStatus status) {
|
||||
if (performance.isDismissed) {
|
||||
if (onDismissed != null)
|
||||
onDismissed();
|
||||
} else if (performance.isCompleted) {
|
||||
if (onCompleted != null)
|
||||
onCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
return buildWithChild(child);
|
||||
}
|
||||
|
||||
Widget buildWithChild(Widget child);
|
||||
|
||||
}
|
||||
|
||||
class SlideTransition extends TransitionBase {
|
||||
class SlideTransition extends TransitionBaseWithChild {
|
||||
SlideTransition({
|
||||
Key key,
|
||||
Anchor anchor,
|
||||
this.position,
|
||||
Duration duration,
|
||||
AnimationPerformance performance,
|
||||
Direction direction,
|
||||
Function onDismissed,
|
||||
Function onCompleted,
|
||||
WatchableAnimationPerformance performance,
|
||||
Widget child
|
||||
}) : super(key: key,
|
||||
anchor: anchor,
|
||||
duration: duration,
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
onDismissed: onDismissed,
|
||||
onCompleted: onCompleted,
|
||||
child: child);
|
||||
|
||||
AnimatedValue<Point> position;
|
||||
|
@ -161,24 +142,14 @@ class SlideTransition extends TransitionBase {
|
|||
}
|
||||
}
|
||||
|
||||
class FadeTransition extends TransitionBase {
|
||||
class FadeTransition extends TransitionBaseWithChild {
|
||||
FadeTransition({
|
||||
Key key,
|
||||
Anchor anchor,
|
||||
this.opacity,
|
||||
Duration duration,
|
||||
AnimationPerformance performance,
|
||||
Direction direction,
|
||||
Function onDismissed,
|
||||
Function onCompleted,
|
||||
WatchableAnimationPerformance performance,
|
||||
Widget child
|
||||
}) : super(key: key,
|
||||
anchor: anchor,
|
||||
duration: duration,
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
onDismissed: onDismissed,
|
||||
onCompleted: onCompleted,
|
||||
child: child);
|
||||
|
||||
AnimatedValue<double> opacity;
|
||||
|
@ -194,24 +165,14 @@ class FadeTransition extends TransitionBase {
|
|||
}
|
||||
}
|
||||
|
||||
class ColorTransition extends TransitionBase {
|
||||
class ColorTransition extends TransitionBaseWithChild {
|
||||
ColorTransition({
|
||||
Key key,
|
||||
Anchor anchor,
|
||||
this.color,
|
||||
Duration duration,
|
||||
AnimationPerformance performance,
|
||||
Direction direction,
|
||||
Function onDismissed,
|
||||
Function onCompleted,
|
||||
WatchableAnimationPerformance performance,
|
||||
Widget child
|
||||
}) : super(key: key,
|
||||
anchor: anchor,
|
||||
duration: duration,
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
onDismissed: onDismissed,
|
||||
onCompleted: onCompleted,
|
||||
child: child);
|
||||
|
||||
AnimatedColorValue color;
|
||||
|
@ -230,25 +191,15 @@ class ColorTransition extends TransitionBase {
|
|||
}
|
||||
}
|
||||
|
||||
class SquashTransition extends TransitionBase {
|
||||
class SquashTransition extends TransitionBaseWithChild {
|
||||
SquashTransition({
|
||||
Key key,
|
||||
Anchor anchor,
|
||||
this.width,
|
||||
this.height,
|
||||
Duration duration,
|
||||
AnimationPerformance performance,
|
||||
Direction direction,
|
||||
Function onDismissed,
|
||||
Function onCompleted,
|
||||
WatchableAnimationPerformance performance,
|
||||
Widget child
|
||||
}) : super(key: key,
|
||||
anchor: anchor,
|
||||
duration: duration,
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
onDismissed: onDismissed,
|
||||
onCompleted: onCompleted,
|
||||
child: child);
|
||||
|
||||
AnimatedValue<double> width;
|
||||
|
@ -274,23 +225,11 @@ typedef Widget BuilderFunction();
|
|||
class BuilderTransition extends TransitionBase {
|
||||
BuilderTransition({
|
||||
Key key,
|
||||
Anchor anchor,
|
||||
this.variables,
|
||||
this.builder,
|
||||
Duration duration,
|
||||
AnimationPerformance performance,
|
||||
Direction direction,
|
||||
Function onDismissed,
|
||||
Function onCompleted,
|
||||
Widget child
|
||||
WatchableAnimationPerformance performance
|
||||
}) : super(key: key,
|
||||
anchor: anchor,
|
||||
duration: duration,
|
||||
performance: performance,
|
||||
direction: direction,
|
||||
onDismissed: onDismissed,
|
||||
onCompleted: onCompleted,
|
||||
child: child);
|
||||
performance: performance);
|
||||
|
||||
List<AnimatedValue> variables;
|
||||
BuilderFunction builder;
|
||||
|
@ -301,7 +240,7 @@ class BuilderTransition extends TransitionBase {
|
|||
super.syncConstructorArguments(source);
|
||||
}
|
||||
|
||||
Widget buildWithChild(Widget child) {
|
||||
Widget build() {
|
||||
for (int i = 0; i < variables.length; ++i)
|
||||
performance.updateVariable(variables[i]);
|
||||
return builder();
|
||||
|
|
Loading…
Reference in a new issue