You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在项目中依次播放不同分组的多张图片动画?

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:26:34