Merge pull request #1413 from Hixie/performance
Simplify AnimationPerformance
This commit is contained in:
commit
1d0573fdf2
@ -43,7 +43,7 @@ abstract class WatchableAnimationPerformance {
|
||||
void removeStatusListener(AnimationPerformanceStatusListener listener);
|
||||
}
|
||||
|
||||
/// A collection of values that animated based on a timeline
|
||||
/// A timeline that can be reversed and used to update [AnimatedVariable]s.
|
||||
///
|
||||
/// For example, a performance may handle an animation of a menu opening by
|
||||
/// sliding and fading in (changing Y value and opacity) over .5 seconds. The
|
||||
@ -52,9 +52,10 @@ abstract class WatchableAnimationPerformance {
|
||||
/// [fling] the timeline causing a physics-based simulation to take over the
|
||||
/// progression.
|
||||
class AnimationPerformance implements WatchableAnimationPerformance {
|
||||
AnimationPerformance({ AnimatedVariable variable, this.duration }) :
|
||||
_variable = variable {
|
||||
AnimationPerformance({ this.duration, double progress }) {
|
||||
_timeline = new Timeline(_tick);
|
||||
if (progress != null)
|
||||
_timeline.value = progress.clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
/// Returns a [WatchableAnimationPerformance] for this performance,
|
||||
@ -65,18 +66,14 @@ class AnimationPerformance implements WatchableAnimationPerformance {
|
||||
/// The length of time this performance should last
|
||||
Duration duration;
|
||||
|
||||
/// The variable being updated by this performance
|
||||
AnimatedVariable get variable => _variable;
|
||||
void set variable(AnimatedVariable variable) { _variable = variable; }
|
||||
AnimatedVariable _variable;
|
||||
|
||||
Timeline _timeline;
|
||||
Direction _direction;
|
||||
|
||||
/// The direction used to select the current curve
|
||||
///
|
||||
/// Curve direction is only reset when we hit the beginning or the end of the
|
||||
/// timeline to avoid discontinuities in the value of the variable.
|
||||
/// timeline to avoid discontinuities in the value of any variables this
|
||||
/// performance is used to animate.
|
||||
Direction _curveDirection;
|
||||
|
||||
/// If non-null, animate with this timing instead of a linear timing
|
||||
@ -85,21 +82,6 @@ class AnimationPerformance implements WatchableAnimationPerformance {
|
||||
/// If non-null, animate with this force instead of a zero-to-one timeline.
|
||||
Force attachedForce;
|
||||
|
||||
/// Add a variable to this animation
|
||||
///
|
||||
/// If there are no attached variables, this variable becomes the value of
|
||||
/// [variable]. Otherwise, all the variables are stored in an [AnimatedList].
|
||||
void addVariable(AnimatedVariable newVariable) {
|
||||
if (variable == null) {
|
||||
variable = newVariable;
|
||||
} else if (variable is AnimatedList) {
|
||||
final AnimatedList variable = this.variable; // TODO(ianh): Remove this line when the analyzer is cleverer
|
||||
variable.variables.add(newVariable);
|
||||
} else {
|
||||
variable = new AnimatedList([variable, newVariable]);
|
||||
}
|
||||
}
|
||||
|
||||
/// The progress of this performance along the timeline
|
||||
///
|
||||
/// Note: Setting this value stops the current animation.
|
||||
@ -238,8 +220,10 @@ class AnimationPerformance implements WatchableAnimationPerformance {
|
||||
|
||||
void _tick(double t) {
|
||||
_updateCurveDirection();
|
||||
if (variable != null)
|
||||
variable.setProgress(_curvedProgress, _curveDirection);
|
||||
didTick(t);
|
||||
}
|
||||
|
||||
void didTick(double t) {
|
||||
_notifyListeners();
|
||||
_checkStatusChanged();
|
||||
}
|
||||
@ -247,11 +231,15 @@ class AnimationPerformance implements WatchableAnimationPerformance {
|
||||
|
||||
/// An animation performance with an animated variable with a concrete type
|
||||
class ValueAnimation<T> extends AnimationPerformance {
|
||||
ValueAnimation({ AnimatedValue<T> variable, Duration duration }) :
|
||||
super(variable: variable, duration: duration);
|
||||
|
||||
AnimatedValue<T> get variable => _variable as AnimatedValue<T>;
|
||||
void set variable(AnimatedValue<T> v) { _variable = v; }
|
||||
ValueAnimation({ this.variable, Duration duration, double progress }) :
|
||||
super(duration: duration, progress: progress);
|
||||
|
||||
AnimatedValue<T> variable;
|
||||
T get value => variable.value;
|
||||
|
||||
void didTick(double t) {
|
||||
if (variable != null)
|
||||
variable.setProgress(_curvedProgress, _curveDirection);
|
||||
super.didTick(t);
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ class _RenderCheckbox extends RenderToggleable {
|
||||
..color = uncheckedColor;
|
||||
|
||||
// The rrect contracts slightly during the animation
|
||||
double inset = 2.0 - (position.value - _kMidpoint).abs() * 2.0;
|
||||
double inset = 2.0 - (position - _kMidpoint).abs() * 2.0;
|
||||
sky.Rect rect = new sky.Rect.fromLTWH(offset.dx + inset, offset.dy + inset,
|
||||
_kEdgeSize - inset, _kEdgeSize - inset);
|
||||
sky.RRect rrect = new sky.RRect()
|
||||
@ -142,19 +142,19 @@ class _RenderCheckbox extends RenderToggleable {
|
||||
canvas.drawRRect(rrect, paint);
|
||||
|
||||
// Radial gradient that changes size
|
||||
if (position.value > 0) {
|
||||
if (position > 0) {
|
||||
paint.setStyle(sky.PaintingStyle.fill);
|
||||
paint.setShader(new sky.Gradient.radial(
|
||||
new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
|
||||
_kEdgeSize * (_kMidpoint - position.value) * 8.0, [
|
||||
_kEdgeSize * (_kMidpoint - position) * 8.0, [
|
||||
const sky.Color(0x00000000),
|
||||
uncheckedColor
|
||||
]));
|
||||
canvas.drawRRect(rrect, paint);
|
||||
}
|
||||
|
||||
if (position.value > _kMidpoint) {
|
||||
double t = (position.value - _kMidpoint) / (1.0 - _kMidpoint);
|
||||
if (position > _kMidpoint) {
|
||||
double t = (position - _kMidpoint) / (1.0 - _kMidpoint);
|
||||
|
||||
// Solid filled rrect
|
||||
paint.setStyle(sky.PaintingStyle.strokeAndFill);
|
||||
|
@ -30,11 +30,11 @@ class InkSplash {
|
||||
_radius = new AnimatedValue<double>(
|
||||
_kSplashInitialSize, end: _targetRadius, curve: easeOut);
|
||||
|
||||
_performance = new AnimationPerformance()
|
||||
..variable = _radius
|
||||
..duration = new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor())
|
||||
..addListener(_handleRadiusChange)
|
||||
..play();
|
||||
_performance = new ValueAnimation<double>(
|
||||
variable: _radius,
|
||||
duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor())
|
||||
)..addListener(_handleRadiusChange)
|
||||
..play();
|
||||
}
|
||||
|
||||
final int pointer;
|
||||
|
@ -35,11 +35,15 @@ abstract class ProgressIndicator extends StatefulComponent {
|
||||
}
|
||||
|
||||
class ProgressIndicatorState extends State<ProgressIndicator> {
|
||||
|
||||
ValueAnimation<double> _performance;
|
||||
|
||||
void initState() {
|
||||
super.initState();
|
||||
_performance = new AnimationPerformance()
|
||||
..duration = const Duration(milliseconds: 1500)
|
||||
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease);
|
||||
_performance = new ValueAnimation<double>(
|
||||
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: ease),
|
||||
duration: const Duration(milliseconds: 1500)
|
||||
);
|
||||
_performance.addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.completed)
|
||||
_restartAnimation();
|
||||
@ -47,9 +51,6 @@ class ProgressIndicatorState extends State<ProgressIndicator> {
|
||||
_performance.play();
|
||||
}
|
||||
|
||||
AnimationPerformance _performance;
|
||||
double get _performanceValue => (_performance.variable as AnimatedValue<double>).value;
|
||||
|
||||
void _restartAnimation() {
|
||||
_performance.progress = 0.0;
|
||||
_performance.play();
|
||||
@ -57,13 +58,13 @@ class ProgressIndicatorState extends State<ProgressIndicator> {
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
if (config.value != null)
|
||||
return config._buildIndicator(context, _performanceValue);
|
||||
return config._buildIndicator(context, _performance.value);
|
||||
|
||||
return new BuilderTransition(
|
||||
variables: [_performance.variable],
|
||||
performance: _performance.view,
|
||||
builder: (BuildContext context) {
|
||||
return config._buildIndicator(context, _performanceValue);
|
||||
return config._buildIndicator(context, _performance.value);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -97,9 +97,9 @@ class _RenderSwitch extends RenderToggleable {
|
||||
_radialReaction = new RadialReaction(
|
||||
center: new Point(_kSwitchSize.width / 2.0, _kSwitchSize.height / 2.0),
|
||||
radius: _kReactionRadius,
|
||||
startPosition: startLocation)
|
||||
..addListener(markNeedsPaint)
|
||||
..show();
|
||||
startPosition: startLocation
|
||||
)..addListener(markNeedsPaint)
|
||||
..show();
|
||||
}
|
||||
|
||||
Future _hideRadialReaction() async {
|
||||
@ -140,10 +140,10 @@ class _RenderSwitch extends RenderToggleable {
|
||||
paint.drawLooper = builder.build();
|
||||
|
||||
// The thumb contracts slightly during the animation
|
||||
double inset = 2.0 - (position.value - 0.5).abs() * 2.0;
|
||||
double inset = 2.0 - (position - 0.5).abs() * 2.0;
|
||||
Point thumbPos = new Point(offset.dx +
|
||||
_kTrackRadius +
|
||||
position.value * (_kTrackWidth - _kTrackRadius * 2),
|
||||
position * (_kTrackWidth - _kTrackRadius * 2),
|
||||
offset.dy + _kSwitchHeight / 2.0);
|
||||
canvas.drawCircle(thumbPos, _kThumbRadius - inset, paint);
|
||||
}
|
||||
|
@ -30,16 +30,16 @@ class RadialReaction {
|
||||
_outerOpacity = new AnimatedValue<double>(0.0, end: _kMaxOpacity, curve: easeOut);
|
||||
_innerCenter = new AnimatedValue<Point>(startPosition, end: center, curve: easeOut);
|
||||
_innerRadius = new AnimatedValue<double>(0.0, end: radius, curve: easeOut);
|
||||
_showPerformance = new AnimationPerformance()
|
||||
..addVariable(_outerOpacity)
|
||||
..addVariable(_innerCenter)
|
||||
..addVariable(_innerRadius)
|
||||
..duration = _kShowDuration;
|
||||
|
||||
_fade = new AnimatedValue(1.0, end: 0.0, curve: easeIn);
|
||||
_hidePerformance = new AnimationPerformance()
|
||||
..addVariable(_fade)
|
||||
..duration =_kHideDuration;
|
||||
_showPerformance = new AnimationPerformance(duration: _kShowDuration)
|
||||
..addListener(() {
|
||||
_showPerformance.updateVariable(_outerOpacity);
|
||||
_showPerformance.updateVariable(_innerCenter);
|
||||
_showPerformance.updateVariable(_innerRadius);
|
||||
});
|
||||
_fade = new ValueAnimation<double>(
|
||||
variable: new AnimatedValue(1.0, end: 0.0, curve: easeIn),
|
||||
duration: _kHideDuration
|
||||
);
|
||||
}
|
||||
|
||||
/// The center of the circle in which the reaction occurs
|
||||
@ -55,8 +55,7 @@ class RadialReaction {
|
||||
|
||||
Future _showComplete;
|
||||
|
||||
AnimationPerformance _hidePerformance;
|
||||
AnimatedValue<double> _fade;
|
||||
ValueAnimation<double> _fade;
|
||||
|
||||
/// Show the reaction
|
||||
///
|
||||
@ -70,13 +69,13 @@ class RadialReaction {
|
||||
/// Returns a future that resolves when the reaction is completely hidden.
|
||||
Future hide() async {
|
||||
await _showComplete;
|
||||
await _hidePerformance.forward();
|
||||
await _fade.forward();
|
||||
}
|
||||
|
||||
/// Call listener whenever the visual appearance of the reaction changes
|
||||
void addListener(Function listener) {
|
||||
_showPerformance.addListener(listener);
|
||||
_hidePerformance.addListener(listener);
|
||||
_fade.addListener(listener);
|
||||
}
|
||||
|
||||
final Paint _outerPaint = new Paint();
|
||||
|
@ -24,13 +24,18 @@ abstract class RenderToggleable extends RenderConstrainedBox {
|
||||
: _value = value,
|
||||
_onChanged = onChanged,
|
||||
super(additionalConstraints: new BoxConstraints.tight(size)) {
|
||||
_performance = new AnimationPerformance()
|
||||
..variable = _position
|
||||
..duration = _kToggleDuration
|
||||
..progress = _value ? 1.0 : 0.0
|
||||
..addListener(markNeedsPaint);
|
||||
_performance = new ValueAnimation<double>(
|
||||
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: easeIn, reverseCurve: easeOut),
|
||||
duration: _kToggleDuration,
|
||||
progress: _value ? 1.0 : 0.0
|
||||
)..addListener(markNeedsPaint);
|
||||
}
|
||||
|
||||
ValueAnimation<double> get performance => _performance;
|
||||
ValueAnimation<double> _performance;
|
||||
|
||||
double get position => _performance.value;
|
||||
|
||||
void handleEvent(sky.Event event, BoxHitTestEntry entry) {
|
||||
if (event.type == 'pointerdown')
|
||||
_tap.addPointer(event);
|
||||
@ -68,15 +73,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
|
||||
|
||||
ValueChanged get onChanged => _onChanged;
|
||||
ValueChanged _onChanged;
|
||||
|
||||
void set onChanged(ValueChanged onChanged) {
|
||||
_onChanged = onChanged;
|
||||
}
|
||||
|
||||
AnimatedValue<double> get position => _position;
|
||||
final AnimatedValue<double> _position =
|
||||
new AnimatedValue<double>(0.0, end: 1.0, curve: easeIn, reverseCurve: easeOut);
|
||||
|
||||
AnimationPerformance get performance => _performance;
|
||||
AnimationPerformance _performance;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user