transitions.dart 5.67 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 AnimatedComponent extends StatefulComponent {
  AnimatedComponent({
19
    Key key,
20
    this.animation
21
  }) : super(key: key) {
22
    assert(animation != null);
23 24
  }

25
  final Animation<Object> animation;
26 27 28

  Widget build(BuildContext context);

29
  /// Subclasses typically do not override this method.
30
  _AnimatedComponentState createState() => new _AnimatedComponentState();
31 32 33

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

38
class _AnimatedComponentState extends State<AnimatedComponent> {
39 40
  void initState() {
    super.initState();
41
    config.animation.addListener(_handleTick);
42 43
  }

44 45 46 47
  void didUpdateConfig(AnimatedComponent oldConfig) {
    if (config.animation != oldConfig.animation) {
      oldConfig.animation.removeListener(_handleTick);
      config.animation.addListener(_handleTick);
48 49 50 51
    }
  }

  void dispose() {
52
    config.animation.removeListener(_handleTick);
53 54 55 56 57
    super.dispose();
  }

  void _handleTick() {
    setState(() {
58
      // The animation's state is our build state, and it changed already.
59 60 61 62 63 64 65 66
    });
  }

  Widget build(BuildContext context) {
    return config.build(context);
  }
}

67
class SlideTransition extends AnimatedComponent {
68
  SlideTransition({
69
    Key key,
70
    Animation<FractionalOffset> position,
71
    this.transformHitTests: true,
72 73
    this.child
  }) : position = position, super(key: key, animation: position);
74

75
  final Animation<FractionalOffset> position;
76 77
  final bool transformHitTests;
  final Widget child;
78

79 80 81 82 83 84
  Widget build(BuildContext context) {
    return new FractionalTranslation(
      translation: position.value,
      transformHitTests: transformHitTests,
      child: child
    );
85 86 87
  }
}

88
class ScaleTransition extends AnimatedComponent {
89 90
  ScaleTransition({
    Key key,
91
    Animation<double> scale,
92
    this.alignment: const FractionalOffset(0.5, 0.5),
93 94
    this.child
  }) : scale = scale, super(key: key, animation: scale);
95

96
  final Animation<double> scale;
97
  final FractionalOffset alignment;
98
  final Widget child;
99

100 101
  Widget build(BuildContext context) {
    double scaleValue = scale.value;
102
    Matrix4 transform = new Matrix4.identity()
103
      ..scale(scaleValue, scaleValue);
104 105 106 107 108 109 110 111
    return new Transform(
      transform: transform,
      alignment: alignment,
      child: child
    );
  }
}

112
class RotationTransition extends AnimatedComponent {
Hixie's avatar
Hixie committed
113 114
  RotationTransition({
    Key key,
115
    Animation<double> turns,
116 117
    this.child
  }) : turns = turns, super(key: key, animation: turns);
Hixie's avatar
Hixie committed
118

119
  final Animation<double> turns;
120
  final Widget child;
Hixie's avatar
Hixie committed
121

122 123 124
  Widget build(BuildContext context) {
    double turnsValue = turns.value;
    Matrix4 transform = new Matrix4.rotationZ(turnsValue * math.PI * 2.0);
Hixie's avatar
Hixie committed
125 126 127 128 129 130 131 132
    return new Transform(
      transform: transform,
      alignment: const FractionalOffset(0.5, 0.5),
      child: child
    );
  }
}

133 134 135
class FadeTransition extends AnimatedComponent {
  FadeTransition({
    Key key,
136
    Animation<double> opacity,
137 138 139
    this.child
  }) : opacity = opacity, super(key: key, animation: opacity);

140
  final Animation<double> opacity;
141 142 143 144 145 146 147
  final Widget child;

  Widget build(BuildContext context) {
    return new Opacity(opacity: opacity.value, child: child);
  }
}

148
class ColorTransition extends AnimatedComponent {
149 150
  ColorTransition({
    Key key,
151
    Animation<Color> color,
152 153
    this.child
  }) : color = color, super(key: key, animation: color);
154

155
  final Animation<Color> color;
156
  final Widget child;
157

158
  Widget build(BuildContext context) {
159 160 161 162 163 164
    return new DecoratedBox(
      decoration: new BoxDecoration(backgroundColor: color.value),
      child: child
    );
  }
}
165

166 167 168 169 170
/// 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.
171 172 173
class RelativeRectTween extends Tween<RelativeRect> {
  RelativeRectTween({ RelativeRect begin, RelativeRect end })
    : super(begin: begin, end: end);
174 175 176 177

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

178
/// Animated version of [Positioned] which takes a specific
179 180
/// [Animation<RelativeRect>] to transition the child's position from a start
/// position to and end position over the lifetime of the animation.
181
///
182
/// Only works if it's the child of a [Stack].
183
class PositionedTransition extends AnimatedComponent {
184 185
  PositionedTransition({
    Key key,
186
    Animation<RelativeRect> rect,
187 188
    this.child
  }) : rect = rect, super(key: key, animation: rect) {
189 190 191
    assert(rect != null);
  }

192
  final Animation<RelativeRect> rect;
193
  final Widget child;
194

195
  Widget build(BuildContext context) {
196 197 198 199 200 201 202 203 204 205
    return new Positioned(
      top: rect.value.top,
      right: rect.value.right,
      bottom: rect.value.bottom,
      left: rect.value.left,
      child: child
    );
  }
}

206 207
typedef Widget TransitionBuilder(BuildContext context, Widget child);

208 209
class AnimatedBuilder extends AnimatedComponent {
  AnimatedBuilder({
210
    Key key,
211
    Animation<Object> animation,
212 213
    this.builder,
    this.child
214
  }) : super(key: key, animation: animation);
215

216 217
  final TransitionBuilder builder;
  final Widget child;
218 219

  Widget build(BuildContext context) {
220
    return builder(context, child);
221 222
  }
}