diff --git a/examples/flutter_gallery/lib/demo/material/bottom_navigation_demo.dart b/examples/flutter_gallery/lib/demo/material/bottom_navigation_demo.dart index 68c59a5dd6..fc6cfe6eef 100644 --- a/examples/flutter_gallery/lib/demo/material/bottom_navigation_demo.dart +++ b/examples/flutter_gallery/lib/demo/material/bottom_navigation_demo.dart @@ -47,7 +47,7 @@ class NavigationIconView { return new FadeTransition( opacity: _animation, child: new SlideTransition( - position: new Tween( + position: new FractionalOffsetTween( begin: const FractionalOffset(0.0, 0.02), // Small offset from the top. end: FractionalOffset.topLeft, ).animate(_animation), diff --git a/examples/flutter_gallery/lib/demo/material/drawer_demo.dart b/examples/flutter_gallery/lib/demo/material/drawer_demo.dart index 2e2e2d15d0..d0ae9ffc4b 100644 --- a/examples/flutter_gallery/lib/demo/material/drawer_demo.dart +++ b/examples/flutter_gallery/lib/demo/material/drawer_demo.dart @@ -38,7 +38,7 @@ class _DrawerDemoState extends State with TickerProviderStateMixin { parent: new ReverseAnimation(_controller), curve: Curves.fastOutSlowIn, ); - _drawerDetailsPosition = new Tween( + _drawerDetailsPosition = new FractionalOffsetTween( begin: const FractionalOffset(0.0, -1.0), end: const FractionalOffset(0.0, 0.0), ).animate(new CurvedAnimation( diff --git a/packages/flutter/lib/src/animation/animation.dart b/packages/flutter/lib/src/animation/animation.dart index ee90d0eefe..1140fe7dbf 100644 --- a/packages/flutter/lib/src/animation/animation.dart +++ b/packages/flutter/lib/src/animation/animation.dart @@ -24,9 +24,9 @@ enum AnimationStatus { /// Signature for listeners attached using [Animation.addStatusListener]. typedef void AnimationStatusListener(AnimationStatus status); -/// An animation with a value of type T +/// An animation with a value of type `T`. /// -/// An animation consists of a value (of type T) together with a status. The +/// An animation consists of a value (of type `T`) together with a status. The /// status indicates whether the animation is conceptually running from /// beginning to end or from the end back to the beginning, although the actual /// value of the animation might not change monotonically (e.g., if the diff --git a/packages/flutter/lib/src/animation/tween.dart b/packages/flutter/lib/src/animation/tween.dart index fc9f3eb2a3..2cf0ce18cc 100644 --- a/packages/flutter/lib/src/animation/tween.dart +++ b/packages/flutter/lib/src/animation/tween.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show Color, Size, Rect; +import 'dart:ui' show Color, Size, Rect, hashValues; import 'package:flutter/foundation.dart'; @@ -10,7 +10,11 @@ import 'animation.dart'; import 'animations.dart'; import 'curves.dart'; -/// An object that can produce a value of type T given an [Animation] as input. +/// An object that can produce a value of type `T` given an [Animation] +/// as input. +/// +/// Typically, the values of the input animation are nominally in the range 0.0 +/// to 1.0. In principle, however, any value could be provided. abstract class Animatable { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -77,14 +81,33 @@ class _ChainedEvaluation extends Animatable { /// [Tween] is useful if you want to interpolate across a range. /// /// To use a [Tween] object with an animation, call the [Tween] object's -/// `animate()` method and pass it the [Animation] object that you want to +/// [animate] method and pass it the [Animation] object that you want to /// modify. /// -/// You can chain [Tween] objects together using the `chain()` method, so that a +/// You can chain [Tween] objects together using the [chain] method, so that a /// single [Animation] object is configured by multiple [Tween] objects called -/// in succession. This is different than calling the `animate()` method twice, +/// in succession. This is different than calling the [animate] method twice, /// which results in two [Animation] separate objects, each configured with a /// single [Tween]. +/// +/// ## Sample usage +/// +/// Suppose `_controller` is an [AnimationController], and we want to create an +/// [Animation] that is controlled by that controller, and save it in +/// `_animation`: +/// +/// ```dart +/// _animation = new Tween( +/// begin: const Offset(100.0, 50.0), +/// end: const Offset(200.0, 300.0), +/// ).animation(_controller); +/// ``` +/// +/// That would provide an `_animation` that, over the lifetime of the +/// `_controller`'s animation, returns a value that depicts a point along the +/// line between the two offsets above. If we used a [MaterialPointArcTween] +/// instead of a [Tween] in the code above, the points would follow a +/// pleasing curve instead of a straight line, with no other changes necessary. class Tween extends Animatable { /// Creates a tween. /// @@ -95,27 +118,38 @@ class Tween extends Animatable { /// The value this variable has at the beginning of the animation. /// - /// Must be non-null before this [Tween] is evaluated. + /// See the constructor for details about whether this property may be null + /// (it varies from subclass to subclass). T begin; /// The value this variable has at the end of the animation. /// - /// Must be non-null before this [Tween] is evaluated. + /// See the constructor for details about whether this property may be null + /// (it varies from subclass to subclass). T end; /// Returns the value this variable has at the given animation clock value. /// - /// The [begin] and [end] properties must be non-null by the time this method - /// is called. - T lerp(double t) => begin + (end - begin) * t; + /// The default implementation of this method uses the [+], [-], and [*] + /// operators on `T`. The [begin] and [end] properties must therefore be + /// non-null by the time this method is called. + T lerp(double t) { + assert(begin != null); + assert(end != null); + return begin + (end - begin) * t; + } /// Returns the interpolated value for the current value of the given animation. /// /// This method returns `begin` and `end` when the animation values are 0.0 or /// 1.0, respectively. /// - /// The [begin] and [end] properties must be non-null by the time this method - /// is called with an animation that is not at 0.0 or 1.0. + /// This function is implemented by deferring to [lerp]. Subclasses that want to + /// provide custom behavior should override [lerp], not [evaluate]. + /// + /// See the constructor for details about whether the [begin] and [end] + /// properties may be null when this is called. It varies from subclass to + /// subclass. @override T evaluate(Animation animation) { final double t = animation.value; @@ -126,67 +160,89 @@ class Tween extends Animatable { return lerp(t); } + @override + bool operator ==(dynamic other) { + if (identical(this, other)) + return true; + if (other.runtimeType != runtimeType) + return false; + final Tween typedOther = other; + return begin == typedOther.begin + && end == typedOther.end; + } + + @override + int get hashCode => hashValues(begin, end); + @override String toString() => '$runtimeType($begin \u2192 $end)'; } /// An interpolation between two colors. /// -/// This class specializes the interpolation of Tween to be -/// appropriate for colors. +/// This class specializes the interpolation of [Tween] to use +/// [Color.lerp]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class ColorTween extends Tween { - /// Creates a color tween. + /// Creates a [Color] tween. /// - /// The [begin] and [end] properties must be non-null before the tween is - /// first used, but the arguments can be null if the values are going to be - /// filled in later. + /// The [begin] and [end] properties may be null; the null value + /// is treated as transparent black. ColorTween({ Color begin, Color end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override Color lerp(double t) => Color.lerp(begin, end, t); } /// An interpolation between two sizes. /// -/// This class specializes the interpolation of Tween to be -/// appropriate for rectangles. +/// This class specializes the interpolation of [Tween] to use +/// [Size.lerp]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class SizeTween extends Tween { - /// Creates a size tween. + /// Creates a [Size] tween. /// - /// The [begin] and [end] properties must be non-null before the tween is - /// first used, but the arguments can be null if the values are going to be - /// filled in later. + /// The [begin] and [end] properties may be null; the null value + /// is treated as an empty size. SizeTween({ Size begin, Size end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override Size lerp(double t) => Size.lerp(begin, end, t); } /// An interpolation between two rectangles. /// -/// This class specializes the interpolation of Tween to be -/// appropriate for rectangles. +/// This class specializes the interpolation of [Tween] to use +/// [Rect.lerp]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class RectTween extends Tween { - /// Creates a rect tween. + /// Creates a [Rect] tween. /// - /// The [begin] and [end] properties must be non-null before the tween is - /// first used, but the arguments can be null if the values are going to be - /// filled in later. + /// The [begin] and [end] properties may be null; the null value + /// is treated as an empty rect at the top left corner. RectTween({ Rect begin, Rect end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override Rect lerp(double t) => Rect.lerp(begin, end, t); } /// An interpolation between two integers that rounds. /// -/// This class specializes the interpolation of Tween to be +/// This class specializes the interpolation of [Tween] to be /// appropriate for integers by interpolating between the given begin /// and end values and then rounding the result to the nearest /// integer. /// -/// This is the closest approximation to a linear tween that is -/// possible with an integer. Compare to [StepTween]. +/// This is the closest approximation to a linear tween that is possible with an +/// integer. Compare to [StepTween] and [Tween]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class IntTween extends Tween { /// Creates an int tween. /// @@ -203,15 +259,17 @@ class IntTween extends Tween { /// An interpolation between two integers that floors. /// -/// This class specializes the interpolation of Tween to be +/// This class specializes the interpolation of [Tween] to be /// appropriate for integers by interpolating between the given begin -/// and end values and then using [int.floor()] to return the current +/// and end values and then using [int.floor] to return the current /// integer component, dropping the fractional component. /// /// This results in a value that is never greater than the equivalent /// value from a linear double interpolation. Compare to [IntTween]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class StepTween extends Tween { - /// Creates a step tween. + /// Creates an [int] tween that floors. /// /// The [begin] and [end] properties must be non-null before the tween is /// first used, but the arguments can be null if the values are going to be diff --git a/packages/flutter/lib/src/material/arc.dart b/packages/flutter/lib/src/material/arc.dart index a9ea773d5f..005f30048b 100644 --- a/packages/flutter/lib/src/material/arc.dart +++ b/packages/flutter/lib/src/material/arc.dart @@ -3,17 +3,20 @@ // found in the LICENSE file. import 'dart:math' as math; -import 'dart:ui' show hashValues, lerpDouble; +import 'dart:ui' show lerpDouble; import 'package:flutter/animation.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; // How close the begin and end points must be to an axis to be considered // vertical or horizontal. const double _kOnAxisDelta = 2.0; -/// A [Tween] that animates an [Offset] along a circular arc. +/// A [Tween] that interpolates an [Offset] along a circular arc. +/// +/// This class specializes the interpolation of [Tween] so that instead +/// of a straight line, the intermediate points follow the arc of a circle in a +/// manner consistent with material design principles. /// /// The arc's radius is related to the bounding box that contains the [begin] /// and [end] points. If the bounding box is taller than it is wide, then the @@ -21,23 +24,27 @@ const double _kOnAxisDelta = 2.0; /// Otherwise the center of the circle will be aligned with the begin point. /// The arc's sweep is always less than or equal to 90 degrees. /// -/// Unlike those of most Tweens, the [begin] and [end] members of a -/// [MaterialPointArcTween] are immutable. -/// /// See also: /// -/// * [MaterialRectArcTween] +/// * [Tween], for a discussion on how to use interpolation objects. +/// * [MaterialRectArcTween], which extends this concept to interpolating [Rect]s. class MaterialPointArcTween extends Tween { /// Creates a [Tween] for animating [Offset]s along a circular arc. /// - /// The [begin] and [end] points are required, cannot be null, and are - /// immutable. + /// The [begin] and [end] properties must be non-null before the tween is + /// first used, but the arguments can be null if the values are going to be + /// filled in later. MaterialPointArcTween({ - @required Offset begin, - @required Offset end - }) : super(begin: begin, end: end) { + Offset begin, + Offset end, + }) : super(begin: begin, end: end); + + bool _dirty = true; + + void _initialize() { assert(begin != null); assert(end != null); + // An explanation with a diagram can be found at https://goo.gl/vMSdRg final Offset delta = end - begin; final double deltaX = delta.dx.abs(); @@ -69,45 +76,85 @@ class MaterialPointArcTween extends Tween { _endAngle = _beginAngle + sweepAngle() * (begin.dx - end.dx).sign; } } + assert(_beginAngle != null); + assert(_endAngle != null); + } else { + _beginAngle = null; + _endAngle = null; + } + _dirty = false; + } + + /// The center of the circular arc, null if [begin] and [end] are horizontally or + /// vertically aligned, or if either is null. + Offset get center { + if (begin == null || end == null) + return null; + if (_dirty) + _initialize(); + return _center; + } + Offset _center; + + /// The radius of the circular arc, null if [begin] and [end] are horizontally or + /// vertically aligned, or if either is null. + double get radius { + if (begin == null || end == null) + return null; + if (_dirty) + _initialize(); + return _radius; + } + double _radius; + + /// The beginning of the arc's sweep in radians, measured from the positive x + /// axis. Positive angles turn clockwise. + /// + /// This will be null if [begin] and [end] are horizontally or vertically + /// aligned, or if either is null. + double get beginAngle { + if (begin == null || end == null) + return null; + if (_dirty) + _initialize(); + return _beginAngle; + } + double _beginAngle; + + /// The end of the arc's sweep in radians, measured from the positive x axis. + /// Positive angles turn clockwise. + /// + /// This will be null if [begin] and [end] are horizontally or vertically + /// aligned, or if either is null. + double get endAngle { + if (begin == null || end == null) + return null; + if (_dirty) + _initialize(); + return _beginAngle; + } + double _endAngle; + + @override + set begin(Offset value) { + if (value != begin) { + super.begin = value; + _dirty = true; } } - Offset _center; - double _radius; - double _beginAngle; - double _endAngle; - - /// The center of the circular arc, null if [begin] and [end] are horiztonally or - /// vertically aligned. - Offset get center => _center; - - /// The radius of the circular arc, null if begin and end are horiztonally or - /// vertically aligned. - double get radius => _radius; - - /// The beginning of the arc's sweep in radians, measured from the positive X axis. - /// Positive angles turn clockwise. Null if begin and end are horiztonally or - /// vertically aligned. - double get beginAngle => _beginAngle; - - /// The end of the arc's sweep in radians, measured from the positive X axis. - /// Positive angles turn clockwise. - double get endAngle => _beginAngle; - - /// Setting the arc's [begin] parameter is not supported. Construct a new arc instead. - @override - set begin(Offset value) { - assert(false); // not supported - } - - /// Setting the arc's [end] parameter is not supported. Construct a new arc instead. @override set end(Offset value) { - assert(false); // not supported + if (value != end) { + super.end = value; + _dirty = true; + } } @override Offset lerp(double t) { + if (_dirty) + _initialize(); if (t == 0.0) return begin; if (t == 1.0) @@ -120,23 +167,9 @@ class MaterialPointArcTween extends Tween { return _center + new Offset(x, y); } - @override - bool operator ==(dynamic other) { - if (identical(this, other)) - return true; - if (other is! MaterialPointArcTween) - return false; - final MaterialPointArcTween typedOther = other; - return begin == typedOther.begin - && end == typedOther.end; - } - - @override - int get hashCode => hashValues(begin, end); - @override String toString() { - return '$runtimeType($begin \u2192 $end center=$center, radius=$radius, beginAngle=$beginAngle, endAngle=$endAngle)'; + return '$runtimeType($begin \u2192 $end; center=$center, radius=$radius, beginAngle=$beginAngle, endAngle=$endAngle)'; } } @@ -176,44 +209,55 @@ T _maxBy(Iterable input, _KeyFunc keyFunc) { return maxValue; } -/// A [Tween] that animates a [Rect] from [begin] to [end]. +/// A [Tween] that interpolates a [Rect] by having its opposite corners follow +/// circular arcs. /// -/// The rectangle corners whose diagonal is closest to the overall direction of -/// the animation follow arcs defined with [MaterialPointArcTween]. +/// This class specializes the interpolation of [Tween] so that instead of +/// growing or shrinking linearly, opposite corners of the rectangle follow arcs +/// in a manner consistent with material design principles. /// -/// Unlike those of most Tweens, the [begin] and [end] members of a -/// [MaterialPointArcTween] are immutable. +/// Specifically, the rectangle corners whose diagonals are closest to the overall +/// direction of the animation follow arcs defined with [MaterialPointArcTween]. /// /// See also: /// -/// * [MaterialPointArcTween]. the analogue for [Offset] interporation. -/// * [RectTween], which does a linear rectangle interpolation. +/// * [Tween], for a discussion on how to use interpolation objects. +/// * [MaterialPointArcTween], the analogue for [Offset] interporation. +/// * [RectTween], which does a linear rectangle interpolation. class MaterialRectArcTween extends RectTween { /// Creates a [Tween] for animating [Rect]s along a circular arc. /// - /// The [begin] and [end] points are required, cannot be null, and are - /// immutable. + /// The [begin] and [end] properties must be non-null before the tween is + /// first used, but the arguments can be null if the values are going to be + /// filled in later. MaterialRectArcTween({ - @required Rect begin, - @required Rect end - }) : super(begin: begin, end: end) { + Rect begin, + Rect end, + }) : super(begin: begin, end: end); + + bool _dirty = true; + + void _initialize() { assert(begin != null); assert(end != null); final Offset centersVector = end.center - begin.center; - _diagonal = _maxBy<_Diagonal>(_allDiagonals, (_Diagonal d) => _diagonalSupport(centersVector, d)); + final _Diagonal diagonal = _maxBy<_Diagonal>(_allDiagonals, (_Diagonal d) => _diagonalSupport(centersVector, d)); _beginArc = new MaterialPointArcTween( - begin: _cornerFor(begin, _diagonal.beginId), - end: _cornerFor(end, _diagonal.beginId) + begin: _cornerFor(begin, diagonal.beginId), + end: _cornerFor(end, diagonal.beginId) ); _endArc = new MaterialPointArcTween( - begin: _cornerFor(begin, _diagonal.endId), - end: _cornerFor(end, _diagonal.endId) + begin: _cornerFor(begin, diagonal.endId), + end: _cornerFor(end, diagonal.endId) ); + _dirty = false; } - _Diagonal _diagonal; - MaterialPointArcTween _beginArc; - MaterialPointArcTween _endArc; + double _diagonalSupport(Offset centersVector, _Diagonal diagonal) { + final Offset delta = _cornerFor(begin, diagonal.endId) - _cornerFor(begin, diagonal.beginId); + final double length = delta.distance; + return centersVector.dx * delta.dx / length + centersVector.dy * delta.dy / length; + } Offset _cornerFor(Rect rect, _CornerId id) { switch (id) { @@ -225,34 +269,48 @@ class MaterialRectArcTween extends RectTween { return Offset.zero; } - double _diagonalSupport(Offset centersVector, _Diagonal diagonal) { - final Offset delta = _cornerFor(begin, diagonal.endId) - _cornerFor(begin, diagonal.beginId); - final double length = delta.distance; - return centersVector.dx * delta.dx / length + centersVector.dy * delta.dy / length; - } - /// The path of the corresponding [begin], [end] rectangle corners that lead /// the animation. - MaterialPointArcTween get beginArc => _beginArc; + MaterialPointArcTween get beginArc { + if (begin == null) + return null; + if (_dirty) + _initialize(); + return _beginArc; + } + MaterialPointArcTween _beginArc; /// The path of the corresponding [begin], [end] rectangle corners that trail /// the animation. - MaterialPointArcTween get endArc => _endArc; + MaterialPointArcTween get endArc { + if (end == null) + return null; + if (_dirty) + _initialize(); + return _endArc; + } + MaterialPointArcTween _endArc; - /// Setting the arc's [begin] parameter is not supported. Construct a new arc instead. @override set begin(Rect value) { - assert(false); // not supported + if (value != begin) { + super.begin = value; + _dirty = true; + } } - /// Setting the arc's [end] parameter is not supported. Construct a new arc instead. @override set end(Rect value) { - assert(false); // not supported + if (value != end) { + super.end = value; + _dirty = true; + } } @override Rect lerp(double t) { + if (_dirty) + _initialize(); if (t == 0.0) return begin; if (t == 1.0) @@ -260,22 +318,8 @@ class MaterialRectArcTween extends RectTween { return new Rect.fromPoints(_beginArc.lerp(t), _endArc.lerp(t)); } - @override - bool operator ==(dynamic other) { - if (identical(this, other)) - return true; - if (other is! MaterialRectArcTween) - return false; - final MaterialRectArcTween typedOther = other; - return begin == typedOther.begin - && end == typedOther.end; - } - - @override - int get hashCode => hashValues(begin, end); - @override String toString() { - return '$runtimeType($begin \u2192 $end beginArc=$beginArc, endArc=$endArc)'; + return '$runtimeType($begin \u2192 $end; beginArc=$beginArc, endArc=$endArc)'; } } diff --git a/packages/flutter/lib/src/material/theme.dart b/packages/flutter/lib/src/material/theme.dart index 8ee93ea099..b4dfd2680a 100644 --- a/packages/flutter/lib/src/material/theme.dart +++ b/packages/flutter/lib/src/material/theme.dart @@ -129,9 +129,18 @@ class Theme extends InheritedWidget { } } -/// An animated value that interpolates [ThemeData]s. +/// An interpolation between two [ThemeData]s. +/// +/// This class specializes the interpolation of [Tween] to call the +/// [ThemeData.lerp] method. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class ThemeDataTween extends Tween { - /// Creates an interpolation between [begin] and [end]. + /// Creates a [ThemeData] tween. + /// + /// The [begin] and [end] properties must be non-null before the tween is + /// first used, but the arguments can be null if the values are going to be + /// filled in later. ThemeDataTween({ ThemeData begin, ThemeData end }) : super(begin: begin, end: end); @override diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 64467517f2..fccbe92c2a 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -441,7 +441,11 @@ class ThemeData { } /// Linearly interpolate between two themes. + /// + /// The arguments must not be null. static ThemeData lerp(ThemeData begin, ThemeData end, double t) { + assert(begin != null); + assert(end != null); return new ThemeData.raw( brightness: t < 0.5 ? begin.brightness : end.brightness, primaryColor: Color.lerp(begin.primaryColor, end.primaryColor, t), diff --git a/packages/flutter/lib/src/rendering/tweens.dart b/packages/flutter/lib/src/rendering/tweens.dart index 3206c2b763..87ee32d87b 100644 --- a/packages/flutter/lib/src/rendering/tweens.dart +++ b/packages/flutter/lib/src/rendering/tweens.dart @@ -9,13 +9,17 @@ import 'package:flutter/painting.dart'; /// /// This class specializes the interpolation of Tween to be /// appropriate for rectangles. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class FractionalOffsetTween extends Tween { /// Creates a fractional offset tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties may be null; the null value + /// is treated as meaning the top left corner. FractionalOffsetTween({ FractionalOffset begin, FractionalOffset end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override FractionalOffset lerp(double t) => FractionalOffset.lerp(begin, end, t); } diff --git a/packages/flutter/lib/src/widgets/dismissible.dart b/packages/flutter/lib/src/widgets/dismissible.dart index f9872a961d..79724b3e3d 100644 --- a/packages/flutter/lib/src/widgets/dismissible.dart +++ b/packages/flutter/lib/src/widgets/dismissible.dart @@ -265,7 +265,7 @@ class _DismissibleState extends State with TickerProviderStateMixin } void _updateMoveAnimation() { - _moveAnimation = new Tween( + _moveAnimation = new FractionalOffsetTween( begin: FractionalOffset.topLeft, end: _directionIsXAxis ? new FractionalOffset(_dragExtent.sign, 0.0) : diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index e7087217b4..e3d3747c4f 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -13,60 +13,104 @@ import 'text.dart'; import 'ticker_provider.dart'; /// An interpolation between two [BoxConstraints]. +/// +/// This class specializes the interpolation of [Tween] to use +/// [BoxConstraints.lerp]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class BoxConstraintsTween extends Tween { - /// Creates a box constraints tween. + /// Creates a [BoxConstraints] tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties may be null; the null value + /// is treated as a tight constraint of zero size. BoxConstraintsTween({ BoxConstraints begin, BoxConstraints end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t); } /// An interpolation between two [Decoration]s. +/// +/// This class specializes the interpolation of [Tween] to use +/// [Decoration.lerp]. +/// +/// Typically this will only have useful results if the [begin] and [end] +/// decorations have the same type; decorations of differing types generally do +/// not have a useful animation defined, and will just jump to the [end] +/// immediately. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class DecorationTween extends Tween { /// Creates a decoration tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties may be null. If both are null, then the + /// result is always null. If [end] is not null, then its lerping logic is + /// used (via [Decoration.lerpTo]). Otherwise, [begin]'s lerping logic is used + /// (via [Decoration.lerpFrom]). DecorationTween({ Decoration begin, Decoration end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override Decoration lerp(double t) => Decoration.lerp(begin, end, t); } /// An interpolation between two [EdgeInsets]s. +/// +/// This class specializes the interpolation of [Tween] to use +/// [EdgeInsets.lerp]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class EdgeInsetsTween extends Tween { - /// Creates an edge insets tween. + /// Creates an [EdgeInsets] tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties may be null; the null value + /// is treated as an [EdgeInsets] with no inset. EdgeInsetsTween({ EdgeInsets begin, EdgeInsets end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override EdgeInsets lerp(double t) => EdgeInsets.lerp(begin, end, t); } /// An interpolation between two [BorderRadius]s. +/// +/// This class specializes the interpolation of [Tween] to use +/// [BorderRadius.lerp]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class BorderRadiusTween extends Tween { - /// Creates a border radius tween. + /// Creates a [BorderRadius] tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties may be null; the null value + /// is treated as a right angle (no radius). BorderRadiusTween({ BorderRadius begin, BorderRadius end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override BorderRadius lerp(double t) => BorderRadius.lerp(begin, end, t); } /// An interpolation between two [Matrix4]s. /// +/// This class specializes the interpolation of [Tween] to be +/// appropriate for transformation matrices. +/// /// Currently this class works only for translations. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class Matrix4Tween extends Tween { /// Creates a [Matrix4] tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties must be non-null before the tween is + /// first used, but the arguments can be null if the values are going to be + /// filled in later. Matrix4Tween({ Matrix4 begin, Matrix4 end }) : super(begin: begin, end: end); @override Matrix4 lerp(double t) { + assert(begin != null); + assert(end != null); // TODO(abarth): We should use [Matrix4.decompose] and animate the // decomposed parameters instead of just animating the translation. final Vector3 beginT = begin.getTranslation(); @@ -78,13 +122,21 @@ class Matrix4Tween extends Tween { /// An interpolation between two [TextStyle]s. /// +/// This class specializes the interpolation of [Tween] to use +/// [TextStyle.lerp]. +/// /// This will not work well if the styles don't set the same fields. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class TextStyleTween extends Tween { /// Creates a text style tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties must be non-null before the tween is + /// first used, but the arguments can be null if the values are going to be + /// filled in later. TextStyleTween({ TextStyle begin, TextStyle end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override TextStyle lerp(double t) => TextStyle.lerp(begin, end, t); } diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart index 2ffe97c148..5e6e37b8ea 100644 --- a/packages/flutter/lib/src/widgets/transitions.dart +++ b/packages/flutter/lib/src/widgets/transitions.dart @@ -293,16 +293,19 @@ class FadeTransition extends AnimatedWidget { /// An interpolation between two relative rects. /// -/// This class specializes the interpolation of Tween to be -/// appropriate for rectangles that are described in terms of offsets from -/// other rectangles. +/// This class specializes the interpolation of [Tween] to +/// use [RelativeRect.tween]. +/// +/// See [Tween] for a discussion on how to use interpolation objects. class RelativeRectTween extends Tween { - /// Creates a relative rect tween. + /// Creates a [RelativeRect] tween. /// - /// The [begin] and [end] arguments must not be null. + /// The [begin] and [end] properties may be null; the null value + /// is treated as [RelativeRect.fill]. RelativeRectTween({ RelativeRect begin, RelativeRect end }) : super(begin: begin, end: end); + /// Returns the value this variable has at the given animation clock value. @override RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t); }