diff --git a/Sources/Motion/Animations/BasicAnimation.swift b/Sources/Motion/Animations/BasicAnimation.swift index d133da2c..53b1a40f 100644 --- a/Sources/Motion/Animations/BasicAnimation.swift +++ b/Sources/Motion/Animations/BasicAnimation.swift @@ -125,7 +125,7 @@ public final class BasicAnimation: ValueAnimation: ValueAnimation Bool { - return hasResolved(value: &_value, epsilon: &resolvingEpsilon, toValue: &_toValue) + return hasResolved(value: &_value, epsilon: &valueEpsilon, toValue: &_toValue) } #if DEBUG @@ -205,6 +205,10 @@ public final class BasicAnimation: ValueAnimation: ValueAnimation: ValueAnimation 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(value: inout SIMDType, epsilon: inout SIMDType.EpsilonType, toValue: inout SIMDType, velocity: inout SIMDType) -> (valueResolved: Bool, velocityResolved: Bool) { + internal func hasResolved(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) } @@ -226,7 +226,7 @@ public final class SpringAnimation: ValueAnimation: ValueAnimation) @_specialize(kind: partial, where SIMDType == SIMD64) @_specialize(kind: partial, where SIMDType == SIMD64) - internal func hasResolved(value: inout SIMDType, epsilon: inout SIMDType.EpsilonType, toValue: inout SIMDType, velocity: inout SIMDType) -> (valueResolved: Bool, velocityResolved: Bool) { + internal func hasResolved(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) } @@ -256,7 +256,7 @@ public final class SpringAnimation: ValueAnimation: ValueAnimation: 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. diff --git a/Sources/Motion/Utilities/CAKeyframeAnimationEmittable.swift b/Sources/Motion/Utilities/CAKeyframeAnimationEmittable.swift index 397a5428..6c0320f3 100644 --- a/Sources/Motion/Utilities/CAKeyframeAnimationEmittable.swift +++ b/Sources/Motion/Utilities/CAKeyframeAnimationEmittable.swift @@ -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 @@ -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) diff --git a/Tests/MotionTests/SpringAnimationTests.swift b/Tests/MotionTests/SpringAnimationTests.swift index c8906dd2..46e1fba8 100644 --- a/Tests/MotionTests/SpringAnimationTests.swift +++ b/Tests/MotionTests/SpringAnimationTests.swift @@ -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