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)
}
}