如何在项目中依次播放不同分组的多张图片动画?
解决UIImageView两组图片动画连续播放的问题
你遇到的核心问题是用错了动画实现方式:UIView.animateKeyframes是用来给视图的可动画属性(比如位置、透明度、缩放等)做关键帧过渡的,但UIImageView的animationImages切换并不是这类能通过UIView动画系统驱动的属性,直接在关键帧里设置会导致覆盖或不生效的问题。而且你两个关键帧的起始时间都是0.0,相当于同时执行,后面的animationImages会直接覆盖前面的,自然达不到连续播放的效果。
下面给你两种靠谱的解决方案:
方法一:利用延迟回调实现连续播放
因为UIImageView的动画时长是我们设置的animationDuration,可以在第一组动画启动后,延迟对应时长再切换到第二组,逻辑简单直接:
import UIKit class ViewController: UIViewController { var one: [UIImage] = [] var two: [UIImage] = [] @IBOutlet weak var animatingImage: UIImageView! override func viewDidLoad() { super.viewDidLoad() one = createImageArray(total: 20, imagePrefix: "images1") two = createImageArray(total: 20, imagePrefix: "images2") // 启动第一组动画 startAnimation(with: one, duration: 2) // 延迟第一组动画时长后,启动第二组 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in guard let self = self else { return } self.startAnimation(with: self.two, duration: 2) // 如果需要在第二组动画结束后做收尾操作,再加一层延迟 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { print("所有动画播放完毕") } } } // 封装动画启动方法,避免重复代码 private func startAnimation(with images: [UIImage], duration: TimeInterval) { animatingImage.stopAnimating() // 先停止之前的动画(防止冲突) animatingImage.animationImages = images animatingImage.animationDuration = duration animatingImage.startAnimating() } func createImageArray(total: Int, imagePrefix: String) -> [UIImage] { var imageArray: [UIImage] = [] for imageCount in 1...total { let imageName = "\(imagePrefix)\(imageCount).jpg" guard let image = UIImage(named: imageName) else { print("加载图片失败:\(imageName)") continue } imageArray.append(image) } return imageArray } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
方法二:用CADisplayLink监听动画结束(更精准)
如果担心延迟时间不够精准(比如动画实际播放时长和设置的有偏差),可以用CADisplayLink监听UIImageView的帧变化,当第一组播放完最后一帧时自动切换到第二组:
import UIKit class ViewController: UIViewController { var one: [UIImage] = [] var two: [UIImage] = [] var displayLink: CADisplayLink? @IBOutlet weak var animatingImage: UIImageView! override func viewDidLoad() { super.viewDidLoad() one = createImageArray(total: 20, imagePrefix: "images1") two = createImageArray(total: 20, imagePrefix: "images2") startFirstAnimation() } private func startFirstAnimation() { animatingImage.stopAnimating() animatingImage.animationImages = one animatingImage.animationDuration = 2 animatingImage.startAnimating() // 启动DisplayLink监听帧变化 displayLink = CADisplayLink(target: self, selector: #selector(checkFirstAnimationProgress)) displayLink?.add(to: .main, forMode: .common) } @objc private func checkFirstAnimationProgress() { guard let currentImage = animatingImage.image, let images = animatingImage.animationImages else { return } // 检测是否播放到最后一帧 if let index = images.firstIndex(of: currentImage), index == images.count - 1 { displayLink?.invalidate() // 停止监听 startSecondAnimation() } } private func startSecondAnimation() { animatingImage.stopAnimating() animatingImage.animationImages = two animatingImage.animationDuration = 2 animatingImage.startAnimating() // 监听第二组动画结束 displayLink = CADisplayLink(target: self, selector: #selector(checkSecondAnimationEnd)) displayLink?.add(to: .main, forMode: .common) } @objc private func checkSecondAnimationEnd() { guard let currentImage = animatingImage.image, let images = animatingImage.animationImages else { return } if let index = images.firstIndex(of: currentImage), index == images.count - 1 { displayLink?.invalidate() print("所有动画播放完毕") } } func createImageArray(total: Int, imagePrefix: String) -> [UIImage] { var imageArray: [UIImage] = [] for imageCount in 1...total { let imageName = "\(imagePrefix)\(imageCount).jpg" guard let image = UIImage(named: imageName) else { print("加载图片失败:\(imageName)") continue } imageArray.append(image) } return imageArray } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
原代码失效的原因补充
- 你两个关键帧的
relativeStartTime都设为0.0,相当于同时执行,第二个关键帧的animationImages = two会直接覆盖第一个的one,导致动画状态混乱。 UIView.animateKeyframes的relativeDuration是相对于总时长的比例(范围0~1),你设为3是完全错误的用法,哪怕调整了时间,也解决不了核心问题——animationImages不属于UIView动画系统能处理的属性。
内容的提问来源于stack exchange,提问作者aleksy.t
相关产品推荐
相关产品推荐

