cruisediary / Pastel

🎨 Gradient animation effect like Instagram
MIT License
3.5k stars 185 forks source link

Animation stops if another view controller is presented #45

Open tapizquent opened 5 years ago

tapizquent commented 5 years ago

My controller includes a ImagePickerController, as soon as that displays, the background stops animating. Any ideas why? and how can i make it move again when the imagePicker dismisses

tapizquent commented 5 years ago

NVM! I fixed it. I just added a var to your PastelView class to check whether is currently animating or not. and if its not, then I startAnimation() inside viewDidAppear.

open class PastelView: UIView {

    public var isAnimating: Bool = false   // This right here!

    private struct Animation {
        static let keyPath = "colors"
        static let key = "ColorChange"
    }

And then in

public func startAnimation() {
    self.isAnimating = true   // Here
    gradient.removeAllAnimations()
    setup()
    animateGradient()
}

extension PastelView: CAAnimationDelegate {
    public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if flag {
             gradient.colors = currentGradientSet()
             animateGradient()
        } else {
            self.isAnimating = false
        }
     }
}

And lastly

override func viewDidLoad() {
    pastelView.startAnimation()
}
override func viewDidAppear(_ animated: Bool) {
    if !pastelView.isAnimating {
        pastelView.startAnimation()
    }
}
tapizquent commented 5 years ago

NVM still opened because animation stops midway. No idea why

Rida-ba commented 4 years ago

Thanks it help me to figure it out.

I did like this in order to keep animation working (Using notification observer):

override func viewDidAppear(_ animated: Bool) {

    super.viewDidAppear(animated)
    /// Notification foreground observer
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name:          UIApplication.willEnterForegroundNotification, object: nil)
}

Then call this :

/// MARK: -  Custom Func
@objc func willEnterForeground() {
    /// Play animation
    if !pastelView.isAnimating {
        print("Play Animation")
        pastelView.startAnimation()
    }
}

In my case it works when my app will enter in foreground and will appear. But you can use the same method with another view controller. (Using Notification and call objc func in another VC)

And don't forget to remove the observer :

NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)

I hope it works for you.

Happy New Year !!!!

ucelme commented 4 years ago

Can you provide the full code to fix animations? I get Use of unresolved identifier 'pastelView'

DorukhanArslan commented 1 year ago

There is no need to hold an extra property (isAnimating) in base class. This will handle all cases:

final class AnimatedGradientViewController: UIViewController {

    private lazy var animatedGradientView: PastelView = {
        ...
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 1. Starts animation when view controller is loaded initially.
        animatedGradientView.startAnimation()

        // Insert animated gradient view as subview once.
        view.insertSubview(animatedGradientView, at: 0)

        // Add 'willEnterForeground' notification observer once. First launch does not count.
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(willEnterForeground),
            name: UIApplication.willEnterForegroundNotification,
            object: nil)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        // View is not appeared at the end of neither dismiss or pop, it means view is seen after
        // dismiss or pop of a view controller.
        guard !isBeingPresented && !isMovingToParent else {
            return
        }

        // 2. Starts animation if view controller is seen after dismiss or pop.
        animatedGradientView.startAnimation()
    }

    @objc
    private func willEnterForeground() {
        // 3. Starts animation if app was entered background, e.g. locked or gone to home screen.
        animatedGradientView.startAnimation()
    }
}