Home > Blockchain >  Alternative Way To Animate Instead Of 'UIView.animate'
Alternative Way To Animate Instead Of 'UIView.animate'

Time:09-27

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.

CodePudding user response:

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.

CodePudding user response:

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: { position in
        self.startAnimation(from: to, to: from)
    }
}
  • Related