Swift Mac OS Animation using Animator Proxy – Part 2

In continuation to the Swift Mac OS Animation Part 1 we will work with Animator Proxy to achieve animation in Mac OS Applications.

Animator Proxy
Some simple Mac OSX Animation can be achieved through the usage of Animator Proxy. Animator proxy is the quickest and easiest way to implement animation effects in views and windows.
The animations caused by using animator proxy is called as Cocoa Animation or Cocoa Animatable Proxy Animation. Animator proxy provides a benefit to achieve animations without using core animation layers.

The way animator proxy works is rather than an UI object changing its own size or origin asks the animator proxy to change its properties values using an animation effect

Swift-AnimatorProxy

For our sample application we will create a colored NSView and use animator proxy to animate it position and size changes

        
class ColoredView:NSView{
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        NSColor.magenta.setFill()
        NSBezierPath(rect: self.bounds).fill()
    }
}
import Cocoa
class ViewController: NSViewController {

    @IBOutlet weak var coloredView:ColoredView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.main.asyncAfter(deadline: .now()+1.0) {
            //self.moveViewWithoutAnimation()
            //self.moveViewWithAnimationDefaultDuration()
            //self.moveViewWithAnimationCustomDuration()
            //self.moveWithWithNestedAnimations()
            //self.animatorProxyAndKeyframeAnimations()
        }
    }
}

The default behavior without using animator proxy would be to jump from position one to position two without any animation effect
Changing a view origin without animation

   
 func moveViewWithoutAnimation(){
        var origin = self.coloredView.frame.origin
        origin.x += 300
        self.coloredView.setFrameOrigin(origin)
    }

In the below method, the origin is changed with the view gliding from position one to position two
Animating with Default Duration using animator proxy

    
func moveViewWithAnimationDefaultDuration(){
        var origin = self.coloredView.frame.origin
        origin.x += 300
        self.coloredView.animator().setFrameOrigin(origin)
    }

Animating with Custom Duration using animator proxy
Next we will try to change the view origin in a slower animation than is provided by default. We are using a 3 sec duration for the animation to take place

    
    func moveViewWithAnimationCustomDuration(){
        NSAnimationContext.beginGrouping()
        NSAnimationContext.current().duration = 3.0
        var origin = self.coloredView.frame.origin
        origin.x += 300
        self.coloredView.animator().setFrameOrigin(origin)
        NSAnimationContext.endGrouping()
    }

Nesting Animation Context
We can using Nesting Animatoon context to provide different durations for different animations

        
    func moveWithWithNestedAnimations(){
        NSAnimationContext.beginGrouping()
        NSAnimationContext.current().duration = 3.0
        var origin = self.coloredView.frame.origin
        origin.x += 300
        self.coloredView.animator().setFrameOrigin(origin)
        
            NSAnimationContext.beginGrouping()
            NSAnimationContext.current().duration = 4.0
            var size = self.coloredView.frame.size
            size.height *= 2
            size.width *= 2
            self.coloredView.animator().setFrameSize(size)
            NSAnimationContext.endGrouping()
        NSAnimationContext.endGrouping()
    }

Combining CABasicAnimation, CAKeyframeAnimation and Animator Proxy
In the next sample we will mix animator proxy with a group of CABasicAnimation and CAKeyframeAnimation

        
    func animatorProxyAndKeyframeAnimations(){
        
        let posAnimation = CAKeyframeAnimation()
        posAnimation.duration = 3.0
        let x = self.coloredView.frame.origin.x
        let y = self.coloredView.frame.origin.y
        posAnimation.values = [CGPoint(x: x, y: y),CGPoint(x: x+100, y: y),CGPoint(x: x+200, y: y),CGPoint(x: x+400, y: y+200)]
        posAnimation.keyTimes = [0.0,0.5,0.8,1.0]
        posAnimation.timingFunctions = [CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear),CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear),CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseIn)]
        posAnimation.autoreverses = true
        posAnimation.repeatCount = Float.greatestFiniteMagnitude

        let sizeAnimation = CABasicAnimation(keyPath: "frameSize")
        sizeAnimation.fromValue = self.coloredView.frame.size
        sizeAnimation.toValue = CGSize(width: 50, height: 50)
        sizeAnimation.duration = 3.0
        sizeAnimation.autoreverses = true
        sizeAnimation.repeatCount = Float.greatestFiniteMagnitude
        
        var existingAnimations = self.coloredView.animations
        existingAnimations["frameOrigin"] = posAnimation
        existingAnimations["frameSize"] = sizeAnimation
        self.coloredView.animations = existingAnimations
        //self.coloredView.animator().setFrameOrigin(CGPoint(x: x+400, y: y))
        self.coloredView.animator().frame = CGRect(x: x+400, y: y+200, width: 50, height: 50)
    }

You can download the code from hereSwift-AnimatorProxy
In Part 3 we will see how View Animations work

Posted in Swift, Swift 3.1 Tagged with: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*