您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

474 行
18 KiB

using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.physics;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.animation {
enum _AnimationDirection {
forward,
reverse,
}
public class AnimationController :
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<float> {
public AnimationController(
float? value = null,
TimeSpan? duration = null,
string debugLabel = null,
float lowerBound = 0.0f,
float upperBound = 1.0f,
TickerProvider vsync = null
) {
D.assert(upperBound >= lowerBound);
D.assert(vsync != null);
this._direction = _AnimationDirection.forward;
this.duration = duration;
this.debugLabel = debugLabel;
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this._ticker = vsync.createTicker(this._tick);
this._internalSetValue(value ?? lowerBound);
}
AnimationController(
float value = 0.0f,
TimeSpan? duration = null,
string debugLabel = null,
TickerProvider vsync = null
) {
D.assert(vsync != null);
this.lowerBound = float.NegativeInfinity;
this.upperBound = float.PositiveInfinity;
this._direction = _AnimationDirection.forward;
this.duration = duration;
this.debugLabel = debugLabel;
this._ticker = vsync.createTicker(this._tick);
this._internalSetValue(value);
}
public static AnimationController unbounded(
float value = 0.0f,
TimeSpan? duration = null,
string debugLabel = null,
TickerProvider vsync = null
) {
return new AnimationController(value, duration, debugLabel, vsync);
}
public readonly float lowerBound;
public readonly float upperBound;
public readonly string debugLabel;
public Animation<float> view {
get { return this; }
}
public TimeSpan? duration;
Ticker _ticker;
public void resync(TickerProvider vsync) {
Ticker oldTicker = this._ticker;
this._ticker = vsync.createTicker(this._tick);
this._ticker.absorbTicker(oldTicker);
}
Simulation _simulation;
public override float value {
get { return this._value; }
}
float _value;
public void setValue(float newValue) {
this.stop();
this._internalSetValue(newValue);
this.notifyListeners();
this._checkStatusChanged();
}
public void reset() {
this.setValue(this.lowerBound);
}
public float velocity {
get {
if (!this.isAnimating) {
return 0.0f;
}
return this._simulation.dx((float) this.lastElapsedDuration.Value.Ticks / TimeSpan.TicksPerSecond);
}
}
void _internalSetValue(float newValue) {
this._value = newValue.clamp(this.lowerBound, this.upperBound);
if (this._value == this.lowerBound) {
this._status = AnimationStatus.dismissed;
}
else if (this._value == this.upperBound) {
this._status = AnimationStatus.completed;
}
else {
this._status = (this._direction == _AnimationDirection.forward)
? AnimationStatus.forward
: AnimationStatus.reverse;
}
}
TimeSpan? lastElapsedDuration {
get { return this._lastElapsedDuration; }
}
TimeSpan? _lastElapsedDuration;
public bool isAnimating {
get { return this._ticker != null && this._ticker.isActive; }
}
_AnimationDirection _direction;
public override AnimationStatus status {
get { return this._status; }
}
AnimationStatus _status;
public TickerFuture forward(float? from = null) {
D.assert(() => {
if (this.duration == null) {
throw new UIWidgetsError(
"AnimationController.forward() called with no default Duration.\n" +
"The \"duration\" property should be set, either in the constructor or later, before " +
"calling the forward() function."
);
}
return true;
});
D.assert(
this._ticker != null,
"AnimationController.forward() called after AnimationController.dispose()\n" +
"AnimationController methods should not be used after calling dispose."
);
this._direction = _AnimationDirection.forward;
if (from != null) {
this.setValue(from.Value);
}
return this._animateToInternal(this.upperBound);
}
public TickerFuture reverse(float? from = null) {
D.assert(() => {
if (this.duration == null) {
throw new UIWidgetsError(
"AnimationController.reverse() called with no default Duration.\n" +
"The \"duration\" property should be set, either in the constructor or later, before " +
"calling the reverse() function."
);
}
return true;
});
D.assert(
this._ticker != null,
"AnimationController.reverse() called after AnimationController.dispose()\n" +
"AnimationController methods should not be used after calling dispose."
);
this._direction = _AnimationDirection.reverse;
if (from != null) {
this.setValue(from.Value);
}
return this._animateToInternal(this.lowerBound);
}
public TickerFuture animateTo(float target, TimeSpan? duration = null, Curve curve = null) {
D.assert(
this._ticker != null,
"AnimationController.animateTo() called after AnimationController.dispose()\n" +
"AnimationController methods should not be used after calling dispose."
);
curve = curve ?? Curves.linear;
this._direction = _AnimationDirection.forward;
return this._animateToInternal(target, duration: duration, curve: curve);
}
TickerFuture animateBack(float target, TimeSpan? duration, Curve curve = null) {
D.assert(
this._ticker != null,
"AnimationController.animateBack() called after AnimationController.dispose()\n" +
"AnimationController methods should not be used after calling dispose."
);
curve = curve ?? Curves.linear;
this._direction = _AnimationDirection.reverse;
return this._animateToInternal(target, duration, curve);
}
TickerFuture _animateToInternal(float target, TimeSpan? duration = null, Curve curve = null) {
curve = curve ?? Curves.linear;
TimeSpan? simulationDuration = duration;
if (simulationDuration == null) {
D.assert(() => {
if (this.duration == null) {
throw new UIWidgetsError(
"AnimationController.animateTo() called with no explicit Duration and no default Duration.\n" +
"Either the \"duration\" argument to the animateTo() method should be provided, or the " +
"\"duration\" property should be set, either in the constructor or later, before " +
"calling the animateTo() function."
);
}
return true;
});
float range = this.upperBound - this.lowerBound;
float remainingFraction = range.isFinite() ? (target - this._value).abs() / range : 1.0f;
simulationDuration = TimeSpan.FromTicks((long) (this.duration.Value.Ticks * remainingFraction));
}
else if (target == this.value) {
simulationDuration = TimeSpan.Zero;
}
this.stop();
if (simulationDuration == TimeSpan.Zero) {
if (this._value != target) {
this._value = target.clamp(this.lowerBound, this.upperBound);
this.notifyListeners();
}
this._status = (this._direction == _AnimationDirection.forward)
? AnimationStatus.completed
: AnimationStatus.dismissed;
this._checkStatusChanged();
return TickerFutureImpl.complete();
}
D.assert(simulationDuration > TimeSpan.Zero);
D.assert(!this.isAnimating);
return this._startSimulation(
new _InterpolationSimulation(this._value, target, simulationDuration.Value, curve));
}
public TickerFuture repeat(float? min = null, float? max = null, bool reverse = false, TimeSpan? period = null) {
min = min ?? this.lowerBound;
max = max ?? this.upperBound;
period = period ?? this.duration;
D.assert(() => {
if (period == null) {
throw new UIWidgetsError(
"AnimationController.repeat() called without an explicit period and with no default Duration.\n" +
"Either the \"period\" argument to the repeat() method should be provided, or the " +
"\"duration\" property should be set, either in the constructor or later, before " +
"calling the repeat() function."
);
}
return true;
});
D.assert(max >= min);
D.assert(max <= this.upperBound && min >= this.lowerBound);
return this.animateWith(new _RepeatingSimulation(this._value, min.Value, max.Value, reverse, period.Value));
}
public TickerFuture fling(float velocity = 1.0f) {
this._direction = velocity < 0.0 ? _AnimationDirection.reverse : _AnimationDirection.forward;
float target = velocity < 0.0f
? this.lowerBound - _kFlingTolerance.distance
: this.upperBound + _kFlingTolerance.distance;
Simulation simulation = new SpringSimulation(_kFlingSpringDescription, this.value,
target, velocity);
simulation.tolerance = _kFlingTolerance;
return this.animateWith(simulation);
}
public TickerFuture animateWith(Simulation simulation) {
D.assert(
this._ticker != null,
"AnimationController.animateWith() called after AnimationController.dispose()\n" +
"AnimationController methods should not be used after calling dispose."
);
this.stop();
return this._startSimulation(simulation);
}
TickerFuture _startSimulation(Simulation simulation) {
D.assert(simulation != null);
D.assert(!this.isAnimating);
this._simulation = simulation;
this._lastElapsedDuration = TimeSpan.Zero;
this._value = simulation.x(0.0f).clamp(this.lowerBound, this.upperBound);
var result = this._ticker.start();
this._status = (this._direction == _AnimationDirection.forward)
? AnimationStatus.forward
: AnimationStatus.reverse;
this._checkStatusChanged();
return result;
}
public void stop(bool canceled = true) {
D.assert(
this._ticker != null,
"AnimationController.stop() called after AnimationController.dispose()\n" +
"AnimationController methods should not be used after calling dispose."
);
this._simulation = null;
this._lastElapsedDuration = null;
this._ticker.stop(canceled: canceled);
}
public override void dispose() {
D.assert(() => {
if (this._ticker == null) {
throw new UIWidgetsError(
"AnimationController.dispose() called more than once.\n" +
"A given " + this.GetType() + " cannot be disposed more than once.\n" +
"The following " + this.GetType() + " object was disposed multiple times:\n" +
" " + this);
}
return true;
});
this._ticker.dispose();
this._ticker = null;
base.dispose();
}
AnimationStatus _lastReportedStatus = AnimationStatus.dismissed;
void _checkStatusChanged() {
AnimationStatus newStatus = this.status;
if (this._lastReportedStatus != newStatus) {
this._lastReportedStatus = newStatus;
this.notifyStatusListeners(newStatus);
}
}
void _tick(TimeSpan elapsed) {
this._lastElapsedDuration = elapsed;
float elapsedInSeconds = (float) elapsed.Ticks / TimeSpan.TicksPerSecond;
D.assert(elapsedInSeconds >= 0.0);
this._value = this._simulation.x(elapsedInSeconds).clamp(this.lowerBound, this.upperBound);
if (this._simulation.isDone(elapsedInSeconds)) {
this._status = (this._direction == _AnimationDirection.forward)
? AnimationStatus.completed
: AnimationStatus.dismissed;
this.stop(canceled: false);
}
this.notifyListeners();
this._checkStatusChanged();
}
public override string toStringDetails() {
string paused = this.isAnimating ? "" : "; paused";
string ticker = this._ticker == null ? "; DISPOSED" : (this._ticker.muted ? "; silenced" : "");
string label = this.debugLabel == null ? "" : "; for " + this.debugLabel;
string more = $"{base.toStringDetails()} {this.value:F3}";
return more + paused + ticker + label;
}
static readonly SpringDescription _kFlingSpringDescription = SpringDescription.withDampingRatio(
mass: 1.0f,
stiffness: 500.0f,
ratio: 1.0f
);
static readonly Tolerance _kFlingTolerance = new Tolerance(
velocity: float.PositiveInfinity,
distance: 0.01f
);
}
class _InterpolationSimulation : Simulation {
internal _InterpolationSimulation(float begin, float end, TimeSpan duration, Curve curve) {
this._begin = begin;
this._end = end;
this._curve = curve;
D.assert(duration.Ticks > 0);
this._durationInSeconds = (float) duration.Ticks / TimeSpan.TicksPerSecond;
}
readonly float _durationInSeconds;
readonly float _begin;
readonly float _end;
readonly Curve _curve;
public override float x(float timeInSeconds) {
float t = (timeInSeconds / this._durationInSeconds).clamp(0.0f, 1.0f);
if (t == 0.0f) {
return this._begin;
}
else if (t == 1.0f) {
return this._end;
}
else {
return this._begin + (this._end - this._begin) * this._curve.transform(t);
}
}
public override float dx(float timeInSeconds) {
float epsilon = this.tolerance.time;
return (this.x(timeInSeconds + epsilon) - this.x(timeInSeconds - epsilon)) / (2 * epsilon);
}
public override bool isDone(float timeInSeconds) {
return timeInSeconds > this._durationInSeconds;
}
}
class _RepeatingSimulation : Simulation {
internal _RepeatingSimulation(float initialValue, float min, float max, bool reverse, TimeSpan period) {
this._min = min;
this._max = max;
this._periodInSeconds = (float) period.Ticks / TimeSpan.TicksPerSecond;
this._initialT = (max == min) ? 0.0f : (initialValue / (max - min)) * (period.Ticks / TimeSpan.TicksPerSecond);
this._reverse = reverse;
D.assert(this._periodInSeconds > 0.0f);
D.assert(this._initialT >= 0.0f);
}
readonly float _min;
readonly float _max;
readonly float _periodInSeconds;
readonly bool _reverse;
readonly float _initialT;
public override float x(float timeInSeconds) {
D.assert(timeInSeconds >= 0.0f);
float totalTimeInSeconds = timeInSeconds + this._initialT;
float t = (totalTimeInSeconds / this._periodInSeconds) % 1.0f;
bool _isPlayingReverse = ((int)(totalTimeInSeconds / this._periodInSeconds)) % 2 == 1;
if (this._reverse && _isPlayingReverse) {
return MathUtils.lerpFloat(this._max, this._min, t);
} else {
return MathUtils.lerpFloat(this._min, this._max, t);
}
}
public override float dx(float timeInSeconds) {
return (this._max - this._min) / this._periodInSeconds;
}
public override bool isDone(float timeInSeconds) {
return false;
}
}
}