skip to Main Content

When using this method to animate, it will stop the animation if the phone is locked then reopened or if the app is switched away from and then switched back to.

I have a StackView Titled "MainFocusStack" that I’m animating:

    //AnimationSizeLOOP
 UIView.animateKeyframes(withDuration: 10, delay: 0, options: [ .autoreverse, .repeat], animations: {
 UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0) { self.mainFocusLabel.transform = CGAffineTransform(scaleX: 1.3, y: 1.3) }
   })
     

What can I do to remedy this?

edit

This animation, and 2 others of similar code (one for glow and another for opacity), are synced with a counter. In the above code it grows for 10 seconds and falls for 10 seconds in synced with the timer.

2

Answers


  1. You could simply start the animation when the app comes back into the foreground, e.g., let us imagine that you moved this animation code to some function:

    func startAnimation() {
        subview.transform = .identity
        UIView.animateKeyframes(withDuration: 2, delay: 0, options: [ .autoreverse, .repeat]) { [self] in
            subview.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
        }
    }
    

    Then you could start this not only in viewDidLoad, but also whenever the app becomes active, by observing UIApplication.didBecomeActiveNotification, e.g.:

    private var observer: NSObjectProtocol?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        configureSubview()
    
        observer = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { [weak self] _ in
            self?.startAnimation()
        }
    }
    
    deinit {
        if let observer = observer {
            NotificationCenter.default.removeObserver(observer)
        }
    }
    

    If you are looking for alternative, UIViewPropertyAnimator can be paused and resumed, picking up from where it left off:

    private let subview = ...
    private var didBecomeActiveObserver: NSObjectProtocol?
    private var willResignActiveObserver: NSObjectProtocol?
    private var animator: UIViewPropertyAnimator?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        configureSubview()
    
        didBecomeActiveObserver = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { [weak self] _ in
            self?.animator?.startAnimation()
        }
    
        willResignActiveObserver = NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: .main) { [weak self] _ in
            self?.animator?.pauseAnimation()
        }
    
        startAnimation(from: .identity, to: CGAffineTransform(scaleX: 1.3, y: 1.3))
    }
    
    deinit {
        NotificationCenter.default.removeObserver(didBecomeActiveObserver!)
        NotificationCenter.default.removeObserver(willResignActiveObserver!)
    }
    
    func startAnimation(from: CGAffineTransform, to: CGAffineTransform) {
        animator = UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1, delay: 0, options: [.curveLinear]) {
            self.subview.transform = to
        } completion: { [weak self] position in
            self?.startAnimation(from: to, to: from)
        }
    }
    
    Login or Signup to reply.
  2. It would be better not to want to resume the animation from where it was when it went into the background. If you really do insist on that, then it’s your responsibility to take care of this. When you go into the background, remember where you are in the animation. When you come back to the foreground, start the animation from that point of the animation.

    Your "place" within the animation (often referred to as the current frame) is signified by the animated layer’s timeOffset, or the timeOffset of the animation object itself. If you’re using a UIViewPropertyAnimator, you can use its fractionComplete.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search