如何手动停止Lottie动画?解决XCode中Lottie后台运行及内存问题
Hey there, let's work through your Lottie animation issues one by one. I'll break down the problems in your current code and provide a fixed version with clear explanations.
- Repeated AnimationView Initialization: Every time you tap the popup button, you create a new
AnimationViewinstance and add it to the view, leaving old instances unremoved—this causes memory bloat over time. - Unmanaged Animation State: When navigating away from the view controller, the animation keeps running in the background, leading to unnecessary memory usage and unexpected restarts when you return.
- No Controlled Stop Mechanism: There's no built-in logic to halt the animation after a specific duration.
Step 1: Reuse AnimationView Instead of Recreating It
Instead of initializing a new AnimationView in the animation() method, use the existing popupView outlet you've already set up. This prevents memory leaks from orphaned animation instances.
Step 2: Manage Animation in View Lifecycle Methods
Pause the animation when the view disappears, and clean up resources when the view controller is destroyed to stop background execution and free memory.
Step 3: Add Timed Stop Logic
Use a delayed dispatch call to stop the animation after your desired duration (e.g., 3 seconds in the example below).
Here's the revised code:
import UIKit import Lottie class CoffeeSpecialFortunePageVC: UIViewController { @IBAction func PopUpIn(_ sender: Any) { animateIn(desiredView: PopupBlur) animateIn(desiredView: popupView) startAnimation() } @IBAction func SuccesBtn(_ sender: UIView) { stopAnimation() animateOut(desiredView: PopupBlur) animateOut(desiredView: popupView) } @IBOutlet var popupView: AnimationView! @IBOutlet var PopupBlur: UIVisualEffectView! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.purple PopupBlur.bounds = self.view.bounds popupView.bounds = CGRect(x: 0, y: 0, width: self.view.bounds.width * 0.9, height: self.view.bounds.height * 0.4) // Initialize Lottie animation once on view load setupAnimation() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // Pause animation when leaving the view to stop background execution stopAnimation() // Clean up resources if we're navigating away from this VC entirely if isMovingFromParent { popupView.removeFromSuperview() popupView = nil } } private func setupAnimation() { // Reuse the existing popupView outlet popupView.animation = Animation.named("check1") popupView.contentMode = .scaleAspectFit popupView.frame = CGRect(x: 0, y: 0, width: 350, height: 350) popupView.center = view.center popupView.stop() // Start with animation paused } private func startAnimation() { // Play animation once (use .loop if you need repeated playback) popupView.play(loopMode: .playOnce) { finished in if finished { print("Animation completed naturally") } } // Stop animation after 3 seconds (adjust the duration as needed) DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in self?.stopAnimation() } } private func stopAnimation() { guard popupView.isAnimationPlaying else { return } popupView.stop() } func animateIn(desiredView: UIView) { guard desiredView.superview == nil else { return } // Avoid duplicate subviews let backgroundView = self.view! backgroundView.addSubview(desiredView) desiredView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2) desiredView.alpha = 0 desiredView.center = backgroundView.center UIView.animate(withDuration: 0.3) { desiredView.transform = .identity desiredView.alpha = 1 } } func animateOut(desiredView: UIView) { UIView.animate(withDuration: 0.3, animations: { desiredView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2) desiredView.alpha = 0 }, completion: { _ in desiredView.removeFromSuperview() // Ensure animation stops if we're removing the AnimationView (desiredView as? AnimationView)?.stop() }) } }
Key Improvements Explained
- Reusable Animation Instance: The
setupAnimation()method initializes the animation once, so we don't create redundantAnimationViewobjects that waste memory. - Lifecycle Awareness:
viewWillDisappearpauses the animation and cleans up resources when leaving the view, preventing background execution and memory leaks. - Timed Stop:
DispatchQueue.main.asyncAftertriggers the animation stop after your specified duration—just change the+3to your desired number of seconds. - Weak Self in Closures: Prevents retain cycles that would keep the view controller in memory unnecessarily.
- Duplicate View Prevention: Checks if a view is already in the hierarchy before adding it, avoiding messy view stacks and extra memory usage.
内容的提问来源于stack exchange,提问作者GurkanEsen

