transitions.dart 8.16 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.

Hixie's avatar
Hixie committed
5 6
import 'dart:math' as math;

7
import 'package:flutter/animation.dart';
8
import 'package:flutter/rendering.dart';
Hixie's avatar
Hixie committed
9
import 'package:vector_math/vector_math_64.dart' show Matrix4;
10

11 12 13
import 'basic.dart';
import 'framework.dart';

14
export 'package:flutter/animation.dart' show AnimationDirection;
15
export 'package:flutter/rendering.dart' show RelativeRect;
16

17 18
abstract class TransitionComponent extends StatefulComponent {
  TransitionComponent({
19
    Key key,
20 21 22
    this.performance
  }) : super(key: key) {
    assert(performance != null);
23 24
  }

25
  final PerformanceView performance;
26

27
  Widget build(BuildContext context);
28

29
  _TransitionState createState() => new _TransitionState();
Hixie's avatar
Hixie committed
30 31 32 33 34

  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    description.add('performance: $performance');
  }
35 36
}

37
class _TransitionState extends State<TransitionComponent> {
38 39 40
  void initState() {
    super.initState();
    config.performance.addListener(_performanceChanged);
41
  }
42

43 44 45 46
  void didUpdateConfig(TransitionComponent oldConfig) {
    if (config.performance != oldConfig.performance) {
      oldConfig.performance.removeListener(_performanceChanged);
      config.performance.addListener(_performanceChanged);
47
    }
48
  }
49

50 51 52 53 54
  void dispose() {
    config.performance.removeListener(_performanceChanged);
    super.dispose();
  }

55 56 57 58
  void _performanceChanged() {
    setState(() {
      // The performance's state is our build state, and it changed already.
    });
59 60
  }

61 62
  Widget build(BuildContext context) {
    return config.build(context);
63
  }
64 65
}

66 67
abstract class TransitionWithChild extends TransitionComponent {
  TransitionWithChild({
68 69
    Key key,
    this.child,
70
    PerformanceView performance
71 72
  }) : super(key: key, performance: performance);

73
  final Widget child;
74

75
  Widget build(BuildContext context) => buildWithChild(context, child);
76

77
  Widget buildWithChild(BuildContext context, Widget child);
78 79
}

80
class SlideTransition extends TransitionWithChild {
81
  SlideTransition({
82 83
    Key key,
    this.position,
84
    PerformanceView performance,
85
    this.transformHitTests: true,
86 87 88 89 90
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

91 92
  final AnimatedValue<FractionalOffset> position;
  bool transformHitTests;
93

94
  Widget buildWithChild(BuildContext context, Widget child) {
95
    performance.updateVariable(position);
96
    return new FractionalTranslation(translation: position.value, transformHitTests: transformHitTests, child: child);
97 98 99
  }
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
class ScaleTransition extends TransitionWithChild {
  ScaleTransition({
    Key key,
    this.scale,
    this.alignment: const FractionalOffset(0.5, 0.5),
    PerformanceView performance,
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

  final AnimatedValue<double> scale;
  final FractionalOffset alignment;

  Widget buildWithChild(BuildContext context, Widget child) {
    performance.updateVariable(scale);
    Matrix4 transform = new Matrix4.identity()
      ..scale(scale.value, scale.value);
    return new Transform(
      transform: transform,
      alignment: alignment,
      child: child
    );
  }
}

Hixie's avatar
Hixie committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
class RotationTransition extends TransitionWithChild {
  RotationTransition({
    Key key,
    this.turns,
    PerformanceView performance,
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

  final AnimatedValue<double> turns;

  Widget buildWithChild(BuildContext context, Widget child) {
    performance.updateVariable(turns);
    Matrix4 transform = new Matrix4.rotationZ(turns.value * math.PI * 2.0);
    return new Transform(
      transform: transform,
      alignment: const FractionalOffset(0.5, 0.5),
      child: child
    );
  }
}

149
class FadeTransition extends TransitionWithChild {
150
  FadeTransition({
151 152
    Key key,
    this.opacity,
153
    PerformanceView performance,
154 155 156 157 158
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

159
  final AnimatedValue<double> opacity;
160

161
  Widget buildWithChild(BuildContext context, Widget child) {
162
    performance.updateVariable(opacity);
163 164 165 166
    return new Opacity(opacity: opacity.value, child: child);
  }
}

167
class ColorTransition extends TransitionWithChild {
168 169 170
  ColorTransition({
    Key key,
    this.color,
171
    PerformanceView performance,
172 173 174 175 176
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

177
  final AnimatedColorValue color;
178

179
  Widget buildWithChild(BuildContext context, Widget child) {
180
    performance.updateVariable(color);
181 182 183 184 185 186
    return new DecoratedBox(
      decoration: new BoxDecoration(backgroundColor: color.value),
      child: child
    );
  }
}
187

188
class SquashTransition extends TransitionWithChild {
189 190 191 192
  SquashTransition({
    Key key,
    this.width,
    this.height,
193
    PerformanceView performance,
194 195 196 197 198
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

199 200
  final AnimatedValue<double> width;
  final AnimatedValue<double> height;
201

202
  Widget buildWithChild(BuildContext context, Widget child) {
203
    if (width != null)
204
      performance.updateVariable(width);
205
    if (height != null)
206
      performance.updateVariable(height);
207
    return new SizedBox(width: width?.value, height: height?.value, child: child);
208 209
  }
}
210

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
class AlignTransition extends TransitionWithChild {
  AlignTransition({
    Key key,
    this.alignment,
    this.widthFactor,
    this.heightFactor,
    PerformanceView performance,
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child);

  final AnimatedValue<FractionalOffset> alignment;
  final AnimatedValue<double> widthFactor;
  final AnimatedValue<double> heightFactor;

  Widget buildWithChild(BuildContext context, Widget child) {
    if (alignment != null)
      performance.updateVariable(alignment);
    if (widthFactor != null)
      performance.updateVariable(widthFactor);
    if (heightFactor != null)
      performance.updateVariable(heightFactor);
    return new Align(
      alignment: alignment?.value,
      widthFactor: widthFactor?.value,
      heightFactor: heightFactor?.value,
238 239
      child: child
    );
240 241 242
  }
}

243 244 245 246 247 248 249 250 251 252 253 254
/// An animated variable containing a RelativeRectangle
///
/// This class specializes the interpolation of AnimatedValue<RelativeRect> to
/// be appropriate for rectangles that are described in terms of offsets from
/// other rectangles.
class AnimatedRelativeRectValue extends AnimatedValue<RelativeRect> {
  AnimatedRelativeRectValue(RelativeRect begin, { RelativeRect end, Curve curve, Curve reverseCurve })
    : super(begin, end: end, curve: curve, reverseCurve: reverseCurve);

  RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t);
}

255 256 257 258 259
/// Animated version of [Positioned] which takes a specific
/// [AnimatedRelativeRectValue] and a [PerformanceView] to transition the
/// child's position from a start position to and end position over the lifetime
/// of the performance.
///
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
/// Only works if it's the child of a [Stack].
class PositionedTransition extends TransitionWithChild {
  PositionedTransition({
    Key key,
    this.rect,
    PerformanceView performance,
    Widget child
  }) : super(key: key,
             performance: performance,
             child: child) {
    assert(rect != null);
  }

  final AnimatedRelativeRectValue rect;

  Widget buildWithChild(BuildContext context, Widget child) {
    performance.updateVariable(rect);
    return new Positioned(
      top: rect.value.top,
      right: rect.value.right,
      bottom: rect.value.bottom,
      left: rect.value.left,
      child: child
    );
  }
}


288
class BuilderTransition extends TransitionComponent {
289 290
  BuilderTransition({
    Key key,
291
    this.variables: const <AnimatedValue>[],
292
    this.builder,
293
    PerformanceView performance
294
  }) : super(key: key,
295
             performance: performance);
296

297
  final List<AnimatedValue> variables;
298
  final WidgetBuilder builder;
299

300
  Widget build(BuildContext context) {
301 302
    for (int i = 0; i < variables.length; ++i)
      performance.updateVariable(variables[i]);
303
    return builder(context);
304 305
  }
}