OGeek|极客世界-中国程序员成长平台

标题: ios - CABasicAnimation 有时有效,有时失败 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-13 16:12
标题: ios - CABasicAnimation 有时有效,有时失败

我正在制作一个应用程序,通过一系列步骤引导用户创建帐户。完成每个步骤后,用户将被带到下一个 View Controller ,并且屏幕顶部会出现一个进度条动画,以传达已完成的帐户创建过程的多少。这是最终结果:

enter image description here

这是通过在包含 View 中放置导航 Controller 来实现的。进度条覆盖在包含 View 上,每次导航 Controller 推送一个新的 View Controller 时,它都会告诉包含 View Controller 将进度条设置为父 View 宽度的某个百分比。这是通过以下 updateProgressBar 函数完成的。

import UIKit

class ContainerVC: UIViewController {
    var progressBar: CAShapeLayer!

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        progressBar = CAShapeLayer()
        progressBar.bounds = CGRect(x: 0, y: 0, width: 0, height: view.safeAreaInsets.top)
        progressBar.position = CGPoint(x: 0, y: 0)
        progressBar.anchorPoint = CGPoint(x: 0, y: 0)
        progressBar.backgroundColor = UIColor.secondaryColor.cgColor
        view.layer.addSublayer(progressBar)
    }

    func updateProgressBar(to percentAsDecimal: CGFloat!) {
        let newWidth = view.bounds.width * percentAsDecimal
        CATransaction.begin()
        CATransaction.setCompletionBlock({
            self.progressBar.bounds.size.width = newWidth
        })
        CATransaction.commit()
        let anim = CABasicAnimation(keyPath: "bounds")
        anim.isRemovedOnCompletion = true
        anim.duration = 0.25
        anim.fromValue = NSValue(cgRect: CGRect(x: 0, y: 0, width: progressBar.bounds.width, height: view.safeAreaInsets.top))
        anim.toValue = NSValue(cgRect: CGRect(x: 0, y: 0, width: newWidth, height: view.safeAreaInsets.top))
        progressBar.add(anim, forKey: "anim")
    }
}

导航 Controller 堆栈中的 View Controller 将在推送下一个 VC 时调用此 updateProgressBar 函数。这样做是这样的:

class FourthViewController: UIViewController {

    var containerVC: ContainerViewController!

    ...

    @IBAction func nextButtonPressed(_ sender: Any) {
        let storyboard = UIStoryboard(name: "Main", bundle: .main)
        let fifthVC = storyboard.instantiateViewController(withIdentifier: "FifthVC") as! FifthViewController
        fifthVC.containerVC = containerVC
        navigationController!.pushViewController(fifthVC, animated: true)
        //We pass 5/11 because the next step will be step 5 out of 11 total steps
        self.containerVC.updateProgressBar(to: 5/11)
    }
}

同理,当按下返回键时,我们收缩容器VC的进度条:

class FourthViewController: UIViewController {

    var containerVC: ContainerViewController!

    ...

    @IBAction func backButtonPressed(_ sender: Any) {
        navigationController!.popViewController(animated: true)

        //We pass 3/11 because the previous step is step 3 out of 11 total steps
        containerVC.updateProgressBar(to: 3/11)
    }
}

我的问题是这个动画有时只能工作。进度条在进程中向前移动时始终有效,但有时,当用户向后导航时,进度条会卡住并且不会再向任一方向移动,直到出现未到达的 View Controller 。请看下面的视频:

Video of Bug (Bug begins around 0:23)

我已确认警报 Controller 的显示不是动画失败的原因,并且还确保动画正在主线程上发生。有什么建议吗?



Best Answer-推荐答案


正如这个答案中很好解释的 here , viewDidLayoutSubviews() 被多次调用。

在您的情况下,每次您从导航堆栈中推送或弹出 View Controller 时,您最终都会实例化一个新的 CAShapeLayer

尝试改用 viewDidAppear()

关于ios - CABasicAnimation 有时有效,有时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57777822/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (https://ogeek.cn/) Powered by Discuz! X3.4