问题描述
我有一个UIImages数组,我试图以一种特殊的方式对其进行动画处理。就像instagram飞镖功能一样。
当动画到达最后一帧时,它会向后移动并到达第一帧,然后继续进行该过程。
到目前为止,我一直在做的是这样:
imageView.animationImages = [myImages]
imageView.animationDuration = 0.9
imageView.animationRepeatCount = 2
imageView.image = imageView.animationImages?.first
imageView.startAnimating()
如果可能的话,如何实现回旋镖循环?
解决方法
我建议我们重写startAnimating()
方法。这样,我们可以提供自己的动画逻辑,并确定下一帧应该是什么。
我们将创建一个frameTimer
,该animationDuration
的每等分部分将替换UIImageView的图像。它将前后遍历图像数组,直到使用stopAnimating()
方法停止为止。
class BoomerangImageView: UIImageView {
// MARK: Overrides
override func startAnimating() {
guard let frames = animationImages,frames.count > 1 else {
return
}
image = frames.first
let timePerFrame = animationDuration / Double(frames.count)
let timer = Timer(fire: Date(timeIntervalSinceNow: timePerFrame),interval: timePerFrame,repeats: true) { [weak self] _ in
self?.changeFrame()
}
RunLoop.current.add(timer,forMode: .common)
frameTimer = timer
}
override func stopAnimating() {
frameTimer?.invalidate()
frameTimer = nil
currentFrameIndex = 0
}
// MARK: Private
private var frameTimer: Timer?
private var isAnimatingForward = true
private var currentFrameIndex = 0 {
didSet {
if let frames = animationImages,currentFrameIndex >= 0,currentFrameIndex < frames.count {
image = frames[currentFrameIndex]
}
}
}
private func changeFrame() {
guard let frames = animationImages,frames.count > 1 else {
stopAnimating()
return
}
let canAnimateForward = currentFrameIndex < frames.count - 1
let canAnimateBackward = currentFrameIndex > 0
isAnimatingForward = (isAnimatingForward && canAnimateForward) || (!isAnimatingForward && !canAnimateBackward)
currentFrameIndex += isAnimatingForward ? 1 : -1
}
}
然后在视图控制器中,按照计划运行动画:
class ViewController: UIViewController {
@IBOutlet weak var imageView: BoomerangImageView!
let frames: [UIImage] = [
// your images here
]
override func viewDidLoad() {
super.viewDidLoad()
imageView.animationImages = frames
imageView.animationDuration = 2
imageView.startAnimating()
}
}
它看起来应该像这样: