Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Sources/Motion/Animations/BasicAnimation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public final class BasicAnimation<Value: SIMDRepresentable>: ValueAnimation<Valu
If the value is outside the range, or we can't determine what it should be, we'll just start from the beginning, since that's already an unexpected state.
*/
internal func attemptToUpdateAccumulatedTimeToMatchValue() {
if !_value.approximatelyEqual(to: _fromValue, epsilon: resolvingEpsilon) && !_value.approximatelyEqual(to: _toValue, epsilon: resolvingEpsilon) {
if !_value.approximatelyEqual(to: _fromValue, epsilon: valueEpsilon) && !_value.approximatelyEqual(to: _toValue, epsilon: valueEpsilon) {
// Try to find out where we are in the animation.
if let accumulatedTime = solveAccumulatedTime(easingFunction: &easingFunction, range: &_range, value: &_value) {
self.accumulatedTime = accumulatedTime * duration
Expand Down Expand Up @@ -162,7 +162,7 @@ public final class BasicAnimation<Value: SIMDRepresentable>: ValueAnimation<Valu

/// Returns whether or not this animation has resolved.
public override func hasResolved() -> Bool {
return hasResolved(value: &_value, epsilon: &resolvingEpsilon, toValue: &_toValue)
return hasResolved(value: &_value, epsilon: &valueEpsilon, toValue: &_toValue)
}

#if DEBUG
Expand Down Expand Up @@ -205,6 +205,10 @@ public final class BasicAnimation<Value: SIMDRepresentable>: ValueAnimation<Valu
set { }
}

public override class var supportsVelocity: Bool {
return false
}

// MARK: - AnimationDriverObserver

public override func tick(frame: AnimationFrame) {
Expand All @@ -221,7 +225,7 @@ public final class BasicAnimation<Value: SIMDRepresentable>: ValueAnimation<Valu

_valueChanged?(value)

if hasResolved(value: &_value, epsilon: &resolvingEpsilon, toValue: &_toValue) {
if hasResolved(value: &_value, epsilon: &valueEpsilon, toValue: &_toValue) {
stop()

completion?()
Expand Down
16 changes: 8 additions & 8 deletions Sources/Motion/Animations/SpringAnimation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,15 @@ public final class SpringAnimation<Value: SIMDRepresentable>: ValueAnimation<Val

/// Returns whether or not the spring animation has resolved. It is considered resolved when the `toValue` is reached, and `velocity` is zero.
public override func hasResolved() -> Bool {
let resolvedState = hasResolved(value: &_value, epsilon: &resolvingEpsilon, toValue: &_toValue, velocity: &_velocity)
let resolvedState = hasResolved(value: &_value, valueEpsilon: &valueEpsilon, velocityEpsilon: &velocityEpsilon, toValue: &_toValue, velocity: &_velocity)
return resolvedState.valueResolved && resolvedState.velocityResolved
}

#if DEBUG
internal func hasResolved<SIMDType: SupportedSIMD>(value: inout SIMDType, epsilon: inout SIMDType.EpsilonType, toValue: inout SIMDType, velocity: inout SIMDType) -> (valueResolved: Bool, velocityResolved: Bool) {
internal func hasResolved<SIMDType: SupportedSIMD>(value: inout SIMDType, valueEpsilon: inout SIMDType.EpsilonType, velocityEpsilon: inout SIMDType.EpsilonType, toValue: inout SIMDType, velocity: inout SIMDType) -> (valueResolved: Bool, velocityResolved: Bool) {
/* Must Be Mirrored Below */

let valueResolved = value.approximatelyEqual(to: toValue, epsilon: epsilon)
let valueResolved = value.approximatelyEqual(to: toValue, epsilon: valueEpsilon)
if !valueResolved {
return (false, false)
}
Expand All @@ -226,7 +226,7 @@ public final class SpringAnimation<Value: SIMDRepresentable>: ValueAnimation<Val
return (valueResolved, true)
}

let velocityResolved = velocity.approximatelyEqual(to: .zero, epsilon: epsilon)
let velocityResolved = velocity.approximatelyEqual(to: .zero, epsilon: velocityEpsilon)
return (valueResolved, velocityResolved)
}
#else
Expand All @@ -244,10 +244,10 @@ public final class SpringAnimation<Value: SIMDRepresentable>: ValueAnimation<Val
@_specialize(kind: partial, where SIMDType == SIMD32<Double>)
@_specialize(kind: partial, where SIMDType == SIMD64<Float>)
@_specialize(kind: partial, where SIMDType == SIMD64<Double>)
internal func hasResolved<SIMDType: SupportedSIMD>(value: inout SIMDType, epsilon: inout SIMDType.EpsilonType, toValue: inout SIMDType, velocity: inout SIMDType) -> (valueResolved: Bool, velocityResolved: Bool) {
internal func hasResolved<SIMDType: SupportedSIMD>(value: inout SIMDType, valueEpsilon: inout SIMDType.EpsilonType, velocityEpsilon: inout SIMDType.EpsilonType, toValue: inout SIMDType, velocity: inout SIMDType) -> (valueResolved: Bool, velocityResolved: Bool) {
/* Must Be Mirrored Above */

let valueResolved = value.approximatelyEqual(to: toValue, epsilon: epsilon)
let valueResolved = value.approximatelyEqual(to: toValue, epsilon: valueEpsilon)
if !valueResolved {
return (false, false)
}
Expand All @@ -256,7 +256,7 @@ public final class SpringAnimation<Value: SIMDRepresentable>: ValueAnimation<Val
return (valueResolved, true)
}

let velocityResolved = velocity.approximatelyEqual(to: .zero, epsilon: epsilon)
let velocityResolved = velocity.approximatelyEqual(to: .zero, epsilon: velocityEpsilon)
return (valueResolved, velocityResolved)
}
#endif
Expand All @@ -280,7 +280,7 @@ public final class SpringAnimation<Value: SIMDRepresentable>: ValueAnimation<Val

_valueChanged?(value)

let resolvedState = hasResolved(value: &_value, epsilon: &resolvingEpsilon, toValue: &_toValue, velocity: &_velocity)
let resolvedState = hasResolved(value: &_value, valueEpsilon: &valueEpsilon, velocityEpsilon: &velocityEpsilon, toValue: &_toValue, velocity: &_velocity)

if resolvedState.valueResolved && resolvedState.velocityResolved {
stop()
Expand Down
7 changes: 5 additions & 2 deletions Sources/Motion/Animations/ValueAnimation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,11 @@ public class ValueAnimation<Value: SIMDRepresentable>: Animation {
return true
}

/// The default tolerance level for an animation to be considered finished.
public var resolvingEpsilon: Value.SIMDType.EpsilonType = 0.01
/// The default tolerance level for the value part of an animation to be considered finished.
public var valueEpsilon: Value.SIMDType.EpsilonType = 0.01

/// The default tolerance level for the velocity part of an animation to be considered finished (if supported).
public var velocityEpsilon: Value.SIMDType.EpsilonType = 0.01

/**
This is meant to be set only by the -onValueChanged: function vs. being set directly. It should be used inside of -tick: only.
Expand Down
4 changes: 2 additions & 2 deletions Sources/Motion/Utilities/CAKeyframeAnimationEmittable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ extension SpringAnimation: CAKeyframeAnimationEmittable where Value: CAKeyframeA
var hasResolved = false
while !hasResolved {
tickOptimized(Value.SIMDType.Scalar(dt), spring: &spring, value: &value, toValue: &_toValue, velocity: &velocity, clampingRange: &_clampingRange)
let resolvedState = self.hasResolved(value: &value, epsilon: &resolvingEpsilon, toValue: &_toValue, velocity: &velocity)
let resolvedState = self.hasResolved(value: &value, valueEpsilon: &valueEpsilon, velocityEpsilon: &velocityEpsilon, toValue: &_toValue, velocity: &velocity)

if resolvesUponReachingToValue {
hasResolved = resolvedState.valueResolved
Expand Down Expand Up @@ -157,7 +157,7 @@ extension BasicAnimation: CAKeyframeAnimationEmittable where Value: CAKeyframeAn
var hasResolved = false
while !hasResolved {
tickOptimized(easingFunction: &easingFunction, range: &_range, fraction: Value.SIMDType.Scalar(t / duration), value: &value)
hasResolved = self.hasResolved(value: &value, epsilon: &resolvingEpsilon, toValue: &_toValue)
hasResolved = self.hasResolved(value: &value, epsilon: &valueEpsilon, toValue: &_toValue)

let nsValue = Value(value).toKeyframeValue()
values.append(nsValue)
Expand Down
3 changes: 2 additions & 1 deletion Tests/MotionTests/SpringAnimationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ final class SpringAnimationTests: XCTestCase {

let spring2 = SpringAnimation(initialValue: CGRect.zero)
spring2.toValue = CGRect(x: 0, y: 0, width: 320, height: 320)
spring2.resolvingEpsilon = 0.1
spring2.valueEpsilon = 0.1
spring2.velocityEpsilon = 0.1

var spring2FrameCount = 0
spring2.onValueChanged { _ in
Expand Down