transitions.dart 7.79 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:sky/animation.dart';
6 7 8
import 'package:sky/src/widgets/animated_component.dart';
import 'package:sky/src/widgets/basic.dart';
import 'package:sky/src/widgets/framework.dart';
9 10
import 'package:vector_math/vector_math.dart';

11
export 'package:sky/animation.dart' show Direction;
12

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
// 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();

  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({
    Key key,
    this.anchoredTo,
    this.child
  }) : super(key: key);

  Anchor anchoredTo;
  Widget child;
  TransitionBase get transition => anchoredTo.transition;

  void initState() {
    if (transition != null)
      watch(transition.performance);
  }

43
  void syncConstructorArguments(_AnchorTransition source) {
44 45 46 47 48 49
    if (transition != null && isWatching(transition.performance))
      unwatch(transition.performance);
    anchoredTo = source.anchoredTo;
    if (transition != null)
      watch(transition.performance);
    child = source.child;
50
    super.syncConstructorArguments(source);
51 52 53 54 55 56 57 58 59
  }

  Widget build() {
    if (transition == null)
      return child;
    return transition.buildWithChild(child);
  }
}

60 61 62 63
abstract class TransitionBase extends AnimatedComponent {
  TransitionBase({
    Key key,
    this.child,
Hixie's avatar
Hixie committed
64
    this.anchor,
65 66 67 68 69 70 71 72
    this.direction,
    this.duration,
    this.performance,
    this.onDismissed,
    this.onCompleted
  }) : super(key: key);

  Widget child;
73
  Anchor anchor;
74 75 76 77 78 79 80
  Direction direction;
  Duration duration;
  AnimationPerformance performance;
  Function onDismissed;
  Function onCompleted;

  void initState() {
81 82 83
    if (anchor != null)
      anchor.transition = this;

84 85 86
    if (performance == null) {
      assert(duration != null);
      performance = new AnimationPerformance(duration: duration);
Hixie's avatar
Hixie committed
87 88
      if (direction == Direction.reverse)
        performance.progress = 1.0;
89 90 91 92 93 94 95
    }
    performance.addStatusListener(_checkStatusChanged);

    watch(performance);
    _start();
  }

96
  void syncConstructorArguments(TransitionBase source) {
97 98 99 100 101 102 103 104
    child = source.child;
    onCompleted = source.onCompleted;
    onDismissed = source.onDismissed;
    duration = source.duration;
    if (direction != source.direction) {
      direction = source.direction;
      _start();
    }
105
    super.syncConstructorArguments(source);
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
  }

  void _start() {
    performance.play(direction);
  }

  void _checkStatusChanged(AnimationStatus status) {
    if (performance.isDismissed) {
      if (onDismissed != null)
        onDismissed();
    } else if (performance.isCompleted) {
      if (onCompleted != null)
        onCompleted();
    }
  }

122 123 124 125 126
  Widget build() {
    return buildWithChild(child);
  }

  Widget buildWithChild(Widget child);
127 128
}

129 130
class SlideTransition extends TransitionBase {
  SlideTransition({
131
    Key key,
132
    Anchor anchor,
133 134 135 136 137 138 139 140
    this.position,
    Duration duration,
    AnimationPerformance performance,
    Direction direction,
    Function onDismissed,
    Function onCompleted,
    Widget child
  }) : super(key: key,
141
             anchor: anchor,
142 143 144 145 146 147 148 149 150
             duration: duration,
             performance: performance,
             direction: direction,
             onDismissed: onDismissed,
             onCompleted: onCompleted,
             child: child);

  AnimatedValue<Point> position;

151
  void syncConstructorArguments(SlideTransition source) {
152
    position = source.position;
153
    super.syncConstructorArguments(source);
154 155
  }

156
  Widget buildWithChild(Widget child) {
157
    performance.updateVariable(position);
158 159 160 161 162 163
    Matrix4 transform = new Matrix4.identity()
      ..translate(position.value.x, position.value.y);
    return new Transform(transform: transform, child: child);
  }
}

164 165
class FadeTransition extends TransitionBase {
  FadeTransition({
166
    Key key,
167
    Anchor anchor,
168 169 170 171 172 173 174 175
    this.opacity,
    Duration duration,
    AnimationPerformance performance,
    Direction direction,
    Function onDismissed,
    Function onCompleted,
    Widget child
  }) : super(key: key,
176
             anchor: anchor,
177 178 179 180 181 182 183 184 185
             duration: duration,
             performance: performance,
             direction: direction,
             onDismissed: onDismissed,
             onCompleted: onCompleted,
             child: child);

  AnimatedValue<double> opacity;

186
  void syncConstructorArguments(FadeTransition source) {
187
    opacity = source.opacity;
188
    super.syncConstructorArguments(source);
189 190
  }

191
  Widget buildWithChild(Widget child) {
192
    performance.updateVariable(opacity);
193 194 195 196 197 198 199
    return new Opacity(opacity: opacity.value, child: child);
  }
}

class ColorTransition extends TransitionBase {
  ColorTransition({
    Key key,
200
    Anchor anchor,
201 202 203 204 205 206 207 208
    this.color,
    Duration duration,
    AnimationPerformance performance,
    Direction direction,
    Function onDismissed,
    Function onCompleted,
    Widget child
  }) : super(key: key,
209
             anchor: anchor,
210 211 212 213 214 215 216 217 218
             duration: duration,
             performance: performance,
             direction: direction,
             onDismissed: onDismissed,
             onCompleted: onCompleted,
             child: child);

  AnimatedColorValue color;

219
  void syncConstructorArguments(ColorTransition source) {
220
    color = source.color;
221
    super.syncConstructorArguments(source);
222 223
  }

224
  Widget buildWithChild(Widget child) {
225
    performance.updateVariable(color);
226 227 228 229 230 231
    return new DecoratedBox(
      decoration: new BoxDecoration(backgroundColor: color.value),
      child: child
    );
  }
}
232 233 234 235

class SquashTransition extends TransitionBase {
  SquashTransition({
    Key key,
236
    Anchor anchor,
237 238 239 240 241 242 243 244 245
    this.width,
    this.height,
    Duration duration,
    AnimationPerformance performance,
    Direction direction,
    Function onDismissed,
    Function onCompleted,
    Widget child
  }) : super(key: key,
246
             anchor: anchor,
247 248 249 250 251 252 253 254 255 256
             duration: duration,
             performance: performance,
             direction: direction,
             onDismissed: onDismissed,
             onCompleted: onCompleted,
             child: child);

  AnimatedValue<double> width;
  AnimatedValue<double> height;

257
  void syncConstructorArguments(SquashTransition source) {
258 259
    width = source.width;
    height = source.height;
260
    super.syncConstructorArguments(source);
261 262
  }

263
  Widget buildWithChild(Widget child) {
264
    if (width != null)
265
      performance.updateVariable(width);
266
    if (height != null)
267
      performance.updateVariable(height);
268
    return new SizedBox(width: width?.value, height: height?.value, child: child);
269 270
  }
}
271 272 273 274 275 276

typedef Widget BuilderFunction();

class BuilderTransition extends TransitionBase {
  BuilderTransition({
    Key key,
277
    Anchor anchor,
278 279 280 281 282 283 284 285 286
    this.variables,
    this.builder,
    Duration duration,
    AnimationPerformance performance,
    Direction direction,
    Function onDismissed,
    Function onCompleted,
    Widget child
  }) : super(key: key,
287
             anchor: anchor,
288 289 290 291 292 293 294 295 296 297
             duration: duration,
             performance: performance,
             direction: direction,
             onDismissed: onDismissed,
             onCompleted: onCompleted,
             child: child);

  List<AnimatedValue> variables;
  BuilderFunction builder;

298
  void syncConstructorArguments(BuilderTransition source) {
299 300
    variables = source.variables;
    builder = source.builder;
301
    super.syncConstructorArguments(source);
302 303
  }

304
  Widget buildWithChild(Widget child) {
305 306 307 308 309
    for (int i = 0; i < variables.length; ++i)
      performance.updateVariable(variables[i]);
    return builder();
  }
}