我想要一些能够模仿ValueAnimator
Android 中 iOS 行为的东西。在正常情况下,我会使用UIView
动画,但不幸的是,我尝试随时间插值的对象值不适用于普通动画。
在我的特定情况下,我使用Lottie
动画,并尝试通过动画更改动画的进度UIView
,但动画不是随时间改变进度值,而是跳转到最终值。例如:
let lottieAnim = ...
lottieAnim.animationProgress = 0
UIView.animate(withDuration: 2) {
lottieAnim.animationProgress = 1
}
Run Code Online (Sandbox Code Playgroud)
此示例不会随着时间的推移对 Lottie 动画进行动画处理,而只是跳至末尾。我知道 Lottie 有播放动画的方法,但我尝试使用自定义动画曲线来设置进度(它是没有有限持续时间的进度动画),这就是为什么我需要使用动画UIView
来插入值。
我需要一些间歇性更新来模仿动画的东西,首先想到的是 AndroidValueAnimator
类。
我整理了一个类,它将ValueAnimator
在某种程度上模仿android,并且允许您在需要时指定自己的动画曲线(默认只是线性的)
使用简单
let valueAnimator = ValueAnimator(duration: 2) { value in
animationView.animationProgress = value
}
valueAnimator.start()
Run Code Online (Sandbox Code Playgroud)
高级用法
let valueAnimator = ValueAnimator(from: 0, to: 100, duration: 60, animationCurveFunction: { time, duration in
return atan(time)*2/Double.pi
}, valueUpdater: { value in
animationView.animationProgress = value
})
valueAnimator.start()
Run Code Online (Sandbox Code Playgroud)
您可以随时取消它,也可以使用:
valueAnimator.cancel()
Run Code Online (Sandbox Code Playgroud)
Swift 5 中的 Value Animator 类
// swiftlint:disable:next private_over_fileprivate
fileprivate var defaultFunction: (TimeInterval, TimeInterval) -> (Double) = { time, duration in
return time / duration
}
class ValueAnimator {
let from: Double
let to: Double
var duration: TimeInterval = 0
var startTime: Date!
var displayLink: CADisplayLink?
var animationCurveFunction: (TimeInterval, TimeInterval) -> (Double)
var valueUpdater: (Double) -> Void
init (from: Double = 0, to: Double = 1, duration: TimeInterval, animationCurveFunction: @escaping (TimeInterval, TimeInterval) -> (Double) = defaultFunction, valueUpdater: @escaping (Double) -> Void) {
self.from = from
self.to = to
self.duration = duration
self.animationCurveFunction = animationCurveFunction
self.valueUpdater = valueUpdater
}
func start() {
displayLink = CADisplayLink(target: self, selector: #selector(update))
displayLink?.add(to: .current, forMode: .default)
}
@objc
private func update() {
if startTime == nil {
startTime = Date()
valueUpdater(from + (to - from) * animationCurveFunction(0, duration))
return
}
var timeElapsed = Date().timeIntervalSince(startTime)
var stop = false
if timeElapsed > duration {
timeElapsed = duration
stop = true
}
valueUpdater(from + (to - from) * animationCurveFunction(timeElapsed, duration))
if stop {
cancel()
}
}
func cancel() {
self.displayLink?.remove(from: .current, forMode: .default)
self.displayLink = nil
}
}
Run Code Online (Sandbox Code Playgroud)
您可能可以将其改进为更通用,但这符合我的目的。
归档时间: |
|
查看次数: |
1095 次 |
最近记录: |