获取在视图层上完成的动画百分比

Getting the percentage of animation completed on view layer

我正在视图 layer 上制作动画 progress bar。我可以暂停和恢复图层动画,但无法获得暂停时完成的动画百分比。

动画代码 视图宽度

 UIView.animate(withDuration: 3, delay: 0, options: .curveLinear, animations: {
        self.progressView.frame.size.width = self.view.bounds.width - 40
 }, completion: nil)

暂停动画

func pauseLayer(layer: CALayer) {
    let pausedTime: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), from: nil)
    layer.speed = 0.0
    layer.timeOffset = pausedTime
}

要恢复的动画代码

func resumeLayer(layer: CALayer) {
    let pausedTime: CFTimeInterval = layer.timeOffset
    layer.speed = 1.0
    layer.timeOffset = 0.0
    layer.beginTime = 0.0
    let timeSincePause: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime

    layer.beginTime = timeSincePause
}

好吧,它可以手动完成,使用下面的代码获取动画的开始时间,当动画停止时调用获取时间的函数以秒为单位然后你可以在代码中划分时间变量下面乘以动画的总时间,然后乘以 100 得到您的百分比 :)

  var startTime: Double = 0
  var time: Double = 0

  /* 
  When the animation starts, record the time and start a timer using the code below
  */
  startTime = Date().timeIntervalSinceReferenceDate

  //When the animation stops, invalidate the timer and do your percentage equation i described above:


  func timeDifference(timer: Timer) {

    //Total time in seconds
    time = Date().timeIntervalSinceReferenceDate - startTime

    //The rest of your code goes here

  }

否则,您可以只创建一个具有所需宽度的变量和另一个在停止动画时保持原始宽度的变量,方程式为:

fabs(current width - original width) * 100 /desired width

诀窍是检查动画层的 presentationLayer。这是您看到的动画模型,以及为什么您在评论中声明宽度从未改变。这是因为一旦添加动画,模型层值和帧就会更新,您所看到的只是 presentationLayer 有点像电影。我需要知道您正在应用哪种类型的动画的原因是这样我就可以知道我试图获得表示层的什么属性。否则你们在关于检查 bounds.width 以确定动画进度的评论中都走在了正确的轨道上。试一试。

import UIKit

class ViewController: UIViewController {

    var fakeProgress = UIView()
    var progressLabel = UILabel()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let progressContainer = UIView(frame:  CGRect(x: 20, y:50, width: self.view.bounds.width - 40, height: 40))
        progressContainer.backgroundColor = UIColor.lightGray
        fakeProgress = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 40))
        fakeProgress.backgroundColor = .green
        self.view.addSubview(progressContainer)
        progressContainer.addSubview(fakeProgress)

        progressLabel.frame = CGRect(x: 0, y: 0, width: 10, height: 40)
        progressLabel.translatesAutoresizingMaskIntoConstraints = false
        progressContainer.addSubview(progressLabel)
        progressLabel.text = "0%"
        progressLabel.leadingAnchor.constraint(equalTo: progressContainer.leadingAnchor, constant: 4).isActive = true
        progressLabel.centerYAnchor.constraint(equalTo: progressContainer.centerYAnchor, constant: 0).isActive = true


        let button = UIButton(frame: CGRect(x: 20, y: self.view.bounds.height - 60, width: self.view.bounds.width - 40, height: 40))
        button.addTarget(self, action: #selector(toggleAnimation), for: .touchUpInside)
        button.setTitle("press for something", for: .normal)
        button.backgroundColor = UIColor.green
        button.setTitleColor(UIColor.white, for: .normal)
        self.view.addSubview(button)


        UIView.animate(withDuration: 3, delay: 0, options: .curveLinear, animations: {
            self.fakeProgress.frame.size.width = progressContainer.bounds.width
        }, completion: { (finished) in
            self.progressLabel.text = "\(100.0)%"
            self.progressLabel.isHidden = false
        })

        pauseLayer(layer: fakeProgress.layer)
    }

    @objc func toggleAnimation(){

        if let presentation = fakeProgress.layer.presentation(){
            let width = presentation.bounds.width
            let progress = (width/(self.view.bounds.width - 40)) * 100
            print("the progress is \(progress)")
            progressLabel.text = "\((ceil(progress * 100))/100)%"
        }else{
             let progress = (fakeProgress.frame.width/(self.view.bounds.width - 40)) * 100
            if progress == 100{
                print("finished")
                progressLabel.text = "\(100)%"
            }else{
                print("not started")
                progressLabel.text = "\(0)%"
            }
        }

        if fakeProgress.layer.speed == 0{
            resumeLayer(layer: fakeProgress.layer)
        }else{
            pauseLayer(layer: fakeProgress.layer)
        }

    }


    func pauseLayer(layer: CALayer) {
        progressLabel.isHidden = false
        let pausedTime: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), from: nil)
        layer.speed = 0.0
        layer.timeOffset = pausedTime
    }

    func resumeLayer(layer: CALayer) {
        progressLabel.isHidden = true
        let pausedTime: CFTimeInterval = layer.timeOffset
        layer.speed = 1.0
        layer.timeOffset = 0.0
        layer.beginTime = 0.0
        let timeSincePause: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime

        layer.beginTime = timeSincePause
    }

}