如何在 UIImageVIew 中向后设置一组 UIImages 的动画 - swift - 以编程方式
How do I animate a set of UIImages backward inside UIImageVIew - swift - programmatically
我有一个 UIImages 数组,我正在尝试以特定方式对其进行动画处理。就像 instagram 的 boomerang 功能一样。
当动画到达最后一帧时它向后移动并到达第一帧并继续该过程。
到目前为止我一直在做的是:
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()
}
}
它应该看起来像这样:
我有一个 UIImages 数组,我正在尝试以特定方式对其进行动画处理。就像 instagram 的 boomerang 功能一样。
当动画到达最后一帧时它向后移动并到达第一帧并继续该过程。
到目前为止我一直在做的是:
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()
}
}
它应该看起来像这样: