Merge pull request #1487 from abarth/merge_curve_into_interval
Give Interval a Curve to apply between start and end
This commit is contained in:
commit
02535f50c1
@ -18,9 +18,8 @@ class ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
|
||||
..variable = new AnimatedValue<double>(
|
||||
0.0,
|
||||
end: 1.0,
|
||||
curve: ease,
|
||||
reverseCurve: ease,
|
||||
interval: new Interval(0.0, 0.9)
|
||||
curve: new Interval(0.0, 0.9, curve: ease),
|
||||
reverseCurve: ease
|
||||
);
|
||||
valueAnimation.addStatusListener((PerformanceStatus status) {
|
||||
if (status == PerformanceStatus.dismissed || status == PerformanceStatus.completed)
|
||||
|
@ -25,70 +25,43 @@ abstract class Animatable {
|
||||
String toString();
|
||||
}
|
||||
|
||||
/// Used by [AnimationPerformance] to convert the timing of a performance to a different timescale.
|
||||
/// Used by [Performance] to convert the timing of a performance to a different timescale.
|
||||
/// For example, by setting different values for the interval and reverseInterval, a performance
|
||||
/// can be made to take longer in one direction that the other.
|
||||
class AnimationTiming {
|
||||
AnimationTiming({
|
||||
this.interval: const Interval(0.0, 1.0),
|
||||
this.reverseInterval,
|
||||
this.curve: linear,
|
||||
this.reverseCurve
|
||||
});
|
||||
AnimationTiming({ this.curve, this.reverseCurve });
|
||||
|
||||
/// The interval during which this timing is active in the forward direction
|
||||
Interval interval;
|
||||
|
||||
/// The interval during which this timing is active in the reverse direction
|
||||
///
|
||||
/// If this field is null, the timing defaults to using [interval] in both directions.
|
||||
Interval reverseInterval;
|
||||
|
||||
/// The curve that this timing applies to the animation clock in the forward direction
|
||||
/// The curve to use in the forward direction
|
||||
Curve curve;
|
||||
|
||||
/// The curve that this timing applies to the animation clock in the reverse direction
|
||||
/// The curve to use in the reverse direction
|
||||
///
|
||||
/// If this field is null, the timing defaults to using [curve] in both directions.
|
||||
/// If this field is null, use [curve] in both directions.
|
||||
Curve reverseCurve;
|
||||
|
||||
/// Applies this timing to the given animation clock value in the given direction
|
||||
double transform(double t, AnimationDirection direction) {
|
||||
Interval interval = _getInterval(direction);
|
||||
if (interval != null)
|
||||
t = interval.transform(t);
|
||||
assert(t >= 0.0 && t <= 1.0);
|
||||
Curve activeCurve = _getActiveCurve(direction);
|
||||
if (activeCurve == null)
|
||||
return t;
|
||||
if (t == 0.0 || t == 1.0) {
|
||||
assert(t == _applyCurve(t, direction).round().toDouble());
|
||||
assert(activeCurve.transform(t).round() == t);
|
||||
return t;
|
||||
}
|
||||
return _applyCurve(t, direction);
|
||||
return activeCurve.transform(t);
|
||||
}
|
||||
|
||||
Interval _getInterval(AnimationDirection direction) {
|
||||
if (direction == AnimationDirection.forward || reverseInterval == null)
|
||||
return interval;
|
||||
return reverseInterval;
|
||||
}
|
||||
|
||||
Curve _getCurve(AnimationDirection direction) {
|
||||
Curve _getActiveCurve(AnimationDirection direction) {
|
||||
if (direction == AnimationDirection.forward || reverseCurve == null)
|
||||
return curve;
|
||||
return reverseCurve;
|
||||
}
|
||||
|
||||
double _applyCurve(double t, AnimationDirection direction) {
|
||||
Curve curve = _getCurve(direction);
|
||||
if (curve == null)
|
||||
return t;
|
||||
return curve.transform(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// An animated variable with a concrete type
|
||||
class AnimatedValue<T extends dynamic> extends AnimationTiming implements Animatable {
|
||||
AnimatedValue(this.begin, { this.end, Interval interval, Interval reverseInterval, Curve curve, Curve reverseCurve })
|
||||
: super(interval: interval, reverseInterval: reverseInterval, curve: curve, reverseCurve: reverseCurve) {
|
||||
AnimatedValue(this.begin, { this.end, Curve curve, Curve reverseCurve })
|
||||
: super(curve: curve, reverseCurve: reverseCurve) {
|
||||
value = begin;
|
||||
}
|
||||
|
||||
@ -125,8 +98,8 @@ class AnimatedValue<T extends dynamic> extends AnimationTiming implements Animat
|
||||
/// This class specializes the interpolation of AnimatedValue<Color> to be
|
||||
/// appropriate for colors.
|
||||
class AnimatedColorValue extends AnimatedValue<Color> {
|
||||
AnimatedColorValue(Color begin, { Color end, Interval interval, Interval reverseInterval, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, interval: interval, reverseInterval: reverseInterval, curve: curve, reverseCurve: reverseCurve);
|
||||
AnimatedColorValue(Color begin, { Color end, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
|
||||
|
||||
Color lerp(double t) => Color.lerp(begin, end, t);
|
||||
}
|
||||
@ -136,8 +109,8 @@ class AnimatedColorValue extends AnimatedValue<Color> {
|
||||
/// This class specializes the interpolation of AnimatedValue<Rect> to be
|
||||
/// appropriate for rectangles.
|
||||
class AnimatedRectValue extends AnimatedValue<Rect> {
|
||||
AnimatedRectValue(Rect begin, { Rect end, Interval interval, Interval reverseInterval, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, interval: interval, reverseInterval: reverseInterval, curve: curve, reverseCurve: reverseCurve);
|
||||
AnimatedRectValue(Rect begin, { Rect end, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
|
||||
|
||||
Rect lerp(double t) => Rect.lerp(begin, end, t);
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ class Linear implements Curve {
|
||||
double transform(double t) => t;
|
||||
}
|
||||
|
||||
/// A curve that is 0.0 until start, then linear from 0.0 to 1.0 at end, then 1.0
|
||||
/// A curve that is 0.0 until start, then curved from 0.0 to 1.0 at end, then 1.0
|
||||
class Interval implements Curve {
|
||||
const Interval(this.start, this.end);
|
||||
const Interval(this.start, this.end, { this.curve: linear });
|
||||
|
||||
/// The smallest value for which this interval is 0.0
|
||||
final double start;
|
||||
@ -37,12 +37,18 @@ class Interval implements Curve {
|
||||
/// The smallest value for which this interval is 1.0
|
||||
final double end;
|
||||
|
||||
/// The curve to apply between [start] and [end]
|
||||
final Curve curve;
|
||||
|
||||
double transform(double t) {
|
||||
assert(start >= 0.0);
|
||||
assert(start <= 1.0);
|
||||
assert(end >= 0.0);
|
||||
assert(end <= 1.0);
|
||||
return ((t - start) / (end - start)).clamp(0.0, 1.0);
|
||||
t = ((t - start) / (end - start)).clamp(0.0, 1.0);
|
||||
if (t == 0.0 || t == 1.0)
|
||||
return t;
|
||||
return curve.transform(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,29 +9,29 @@ import 'package:sky/src/widgets/framework.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class AnimatedBoxConstraintsValue extends AnimatedValue<BoxConstraints> {
|
||||
AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve: linear })
|
||||
: super(begin, end: end, curve: curve);
|
||||
AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
|
||||
|
||||
BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t);
|
||||
}
|
||||
|
||||
class AnimatedBoxDecorationValue extends AnimatedValue<BoxDecoration> {
|
||||
AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve: linear })
|
||||
: super(begin, end: end, curve: curve);
|
||||
AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
|
||||
|
||||
BoxDecoration lerp(double t) => BoxDecoration.lerp(begin, end, t);
|
||||
}
|
||||
|
||||
class AnimatedEdgeDimsValue extends AnimatedValue<EdgeDims> {
|
||||
AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve: linear })
|
||||
: super(begin, end: end, curve: curve);
|
||||
AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
|
||||
|
||||
EdgeDims lerp(double t) => EdgeDims.lerp(begin, end, t);
|
||||
}
|
||||
|
||||
class AnimatedMatrix4Value extends AnimatedValue<Matrix4> {
|
||||
AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve: linear })
|
||||
: super(begin, end: end, curve: curve);
|
||||
AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve, Curve reverseCurve })
|
||||
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
|
||||
|
||||
Matrix4 lerp(double t) {
|
||||
// TODO(mpcomplete): Animate the full matrix. Will animating the cells
|
||||
|
@ -12,7 +12,7 @@ import 'package:sky/src/widgets/gesture_detector.dart';
|
||||
|
||||
const Duration _kCardDismissFadeout = const Duration(milliseconds: 200);
|
||||
const Duration _kCardDismissResize = const Duration(milliseconds: 300);
|
||||
final Interval _kCardDismissResizeInterval = new Interval(0.4, 1.0);
|
||||
const Curve _kCardDismissResizeCurve = const Interval(0.4, 1.0, curve: ease);
|
||||
const double _kMinFlingVelocity = 700.0;
|
||||
const double _kMinFlingVelocityDelta = 400.0;
|
||||
const double _kFlingVelocityScale = 1.0 / 300.0;
|
||||
@ -226,8 +226,7 @@ class DismissableState extends State<Dismissable> {
|
||||
AnimatedValue<double> squashAxisExtent = new AnimatedValue<double>(
|
||||
_directionIsYAxis ? _size.width : _size.height,
|
||||
end: 0.0,
|
||||
curve: ease,
|
||||
interval: _kCardDismissResizeInterval
|
||||
curve: _kCardDismissResizeCurve
|
||||
);
|
||||
|
||||
return new SquashTransition(
|
||||
|
@ -29,7 +29,7 @@ const double _kMenuVerticalPadding = 8.0;
|
||||
|
||||
typedef List<PopupMenuItem> PopupMenuItemsBuilder(NavigatorState navigator);
|
||||
|
||||
class PopupMenu extends StatefulComponent {
|
||||
class PopupMenu extends StatelessComponent {
|
||||
PopupMenu({
|
||||
Key key,
|
||||
this.items,
|
||||
@ -46,76 +46,46 @@ class PopupMenu extends StatefulComponent {
|
||||
final NavigatorState navigator;
|
||||
final PerformanceView performance;
|
||||
|
||||
PopupMenuState createState() => new PopupMenuState();
|
||||
}
|
||||
|
||||
class PopupMenuState extends State<PopupMenu> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
config.performance.addListener(_performanceChanged);
|
||||
}
|
||||
|
||||
void didUpdateConfig(PopupMenu oldConfig) {
|
||||
if (config.performance != oldConfig.performance) {
|
||||
oldConfig.performance.removeListener(_performanceChanged);
|
||||
config.performance.addListener(_performanceChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
config.performance.removeListener(_performanceChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _performanceChanged() {
|
||||
setState(() {
|
||||
// the performance changed, and our state is tied up with the performance
|
||||
});
|
||||
}
|
||||
|
||||
BoxPainter _painter;
|
||||
|
||||
void _updateBoxPainter(BoxDecoration decoration) {
|
||||
if (_painter == null || _painter.decoration != decoration)
|
||||
_painter = new BoxPainter(decoration);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
_updateBoxPainter(new BoxDecoration(
|
||||
final BoxPainter painter = new BoxPainter(new BoxDecoration(
|
||||
backgroundColor: Theme.of(context).canvasColor,
|
||||
borderRadius: 2.0,
|
||||
boxShadow: shadows[config.level]
|
||||
boxShadow: shadows[level]
|
||||
));
|
||||
double unit = 1.0 / (config.items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade.
|
||||
|
||||
double unit = 1.0 / (items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade.
|
||||
List<Widget> children = [];
|
||||
for (int i = 0; i < config.items.length; ++i) {
|
||||
|
||||
for (int i = 0; i < items.length; ++i) {
|
||||
double start = (i + 1) * unit;
|
||||
double end = (start + 1.5 * unit).clamp(0.0, 1.0);
|
||||
children.add(new FadeTransition(
|
||||
performance: config.performance,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(start, end)),
|
||||
performance: performance,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(start, end)),
|
||||
child: new InkWell(
|
||||
onTap: () { config.navigator.pop(config.items[i].value); },
|
||||
child: config.items[i]
|
||||
onTap: () { navigator.pop(items[i].value); },
|
||||
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 * config.items.length));
|
||||
|
||||
final width = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, unit));
|
||||
final height = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, unit * items.length));
|
||||
|
||||
return new FadeTransition(
|
||||
performance: config.performance,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, interval: new Interval(0.0, 1.0 / 3.0)),
|
||||
performance: performance,
|
||||
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, 1.0 / 3.0)),
|
||||
child: new Container(
|
||||
margin: new EdgeDims.all(_kMenuMargin),
|
||||
child: new BuilderTransition(
|
||||
performance: config.performance,
|
||||
performance: performance,
|
||||
variables: [width, height],
|
||||
builder: (BuildContext context) {
|
||||
return new CustomPaint(
|
||||
callback: (sky.Canvas canvas, Size size) {
|
||||
double widthValue = width.value * size.width;
|
||||
double heightValue = height.value * size.height;
|
||||
_painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue));
|
||||
painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue));
|
||||
},
|
||||
child: new ConstrainedBox(
|
||||
constraints: new BoxConstraints(
|
||||
@ -162,7 +132,7 @@ class MenuRoute extends Route {
|
||||
Performance createPerformance() {
|
||||
Performance result = super.createPerformance();
|
||||
AnimationTiming timing = new AnimationTiming();
|
||||
timing.reverseInterval = new Interval(0.0, _kMenuCloseIntervalEnd);
|
||||
timing.reverseCurve = new Interval(0.0, _kMenuCloseIntervalEnd);
|
||||
result.timing = timing;
|
||||
return result;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user