Search code examples
swiftanimationcore-animationappkit

Animate NSImageView translation


I'm trying to animate an NSImageView so it slides down a few points and fades-in while doing so. After searching around a few hours I've only managed to get the alpha value to animate. Translating the view works, but it's not animated and I can't figure out why.

import Cocoa

class ViewController: NSViewController {

    @IBOutlet weak var logo: NSImageView!
    @IBAction func doAnimation(_ sender: Any) {

        animateLogo()

    }

    private func animateLogo() {
        let top = CATransform3DMakeTranslation(0, 30, 0)
        logo.wantsLayer = true

        NSAnimationContext.runAnimationGroup({ (context) in
            Swift.print("Running animation")
            context.duration = 5
            logo.animator().alphaValue = 0

            logo.layer?.transform = top
        }, completionHandler: {
            Swift.print("Finished animation")
        })
    }

}

Another approach I've tried in translating the NSView is

logo.animator().translateOrigin(to: new_origin)

Solution

  • If you are using auto layout you can add an outlet to one of your constraints and change the constant value through the animator.

    Example

    Here I have a view with a label and a button

    My view

    The label has two constraints.

    • It is centred horizontally in the view
    • It has a distance of 80 to the bottom of the view

    I can now find the "distance to bottom" outlet in the Document Outline

    this guy

    And ctrl drag it to my corresponding NSViewController where I create an outlet for it.

    @IBOutlet weak var distanceToBottom: NSLayoutConstraint!
    

    I can verify that the outlet is set by looking at the Connections Inspector in the right side of the screen

    enter image description here

    Last step is to animate the view. Here I'm just using an IBAction on a NSButton like so:

    @IBAction func animate(_ sender: NSButton) {
        distanceToBottom.animator().constant = 5
    }
    

    If I run that my label animates nicely to its new position 5 pixels from the bottom.

    final result

    Hope that helps you.