Animate custom presentation of ViewController in OS X Yosemite
Asked Answered
L

2

10

I want to implement new method, I searched a lot on Google and Stack Overflow but I have not found an example.

- (void)presentViewController:(NSViewController *)viewController animator:(id <NSViewControllerPresentationAnimator>)animator

this method is available in OSX 10.10 and this method need to implement the protocol NSViewControllerPresentationAnimator which has these two methods

- (void)animatePresentationOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController 

- (void)animateDismissalOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController 

These methods allow us to do custom animation between two NSViewController's I need an example of implementation, I have this code:

- (IBAction)openTask:(id)sender {
    
    NSStoryboard *storyboard = [NSStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    Tasks *task = [storyboard instantiateControllerWithIdentifier:@"tasks"];
    [self presentViewController:task animator:self];
 
}

- (void)animatePresentationOfViewController:(NSViewController *)viewController
                         fromViewController:(NSViewController *)fromViewController
{
    
    
}

- (void)animateDismissalOfViewController:(NSViewController *)viewController
                      fromViewController:(NSViewController *)fromViewController
{
    
    
}

Can anyone help me with an example of how I could have implemented this transition?

Lordling answered 3/11, 2014 at 13:44 Comment(1)
Is there more help you need or is my example enough?Truck
T
16

Here is a simple version (Swift) that fades in the new viewcontroller's view. I am sure you can translate that into Objective-C.

You will want to actually use Autolayout instead of just changing the frame, but that would have made the example a bit longer (not too difficult. Just add constraints after you add the view)

I am not sure if you need viewcontroller containment as well. Then there would need to be the appropriate calls to addChildViewController and so on. Maybe someone can shed some light on when this might be necessary or if it is actually good practice in any case.

class MyTransitionAnimator: NSObject, NSViewControllerPresentationAnimator {

    func animatePresentationOfViewController(viewController: NSViewController, fromViewController: NSViewController) {

        let bottomVC = fromViewController
        let topVC = viewController

        // make sure the view has a CA layer for smooth animation
        topVC.view.wantsLayer = true

        // set redraw policy
        topVC.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay

        // start out invisible
        topVC.view.alphaValue = 0

        // add view of presented viewcontroller
        bottomVC.view.addSubview(topVC.view)

        // adjust size
        topVC.view.frame = bottomVC.view.frame

        // Do some CoreAnimation stuff to present view
        NSAnimationContext.runAnimationGroup({ (context) -> Void in

            // fade duration
            context.duration = 2
            // animate to alpha 1
            topVC.view.animator().alphaValue = 1

        }, completionHandler: nil)

    }

    func animateDismissalOfViewController(viewController: NSViewController, fromViewController: NSViewController) {

        let bottomVC = fromViewController
        let topVC = viewController

        // make sure the view has a CA layer for smooth animation
        topVC.view.wantsLayer = true

        // set redraw policy
        topVC.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay

        // Do some CoreAnimation stuff to present view
        NSAnimationContext.runAnimationGroup({ (context) -> Void in

            // fade duration
            context.duration = 2
            // animate view to alpha 0
            topVC.view.animator().alphaValue = 0

        }, completionHandler: {

            // remove view
            topVC.view.removeFromSuperview()
        })

    }
}

Hope this gets you started!

Truck answered 3/11, 2014 at 16:3 Comment(1)
Oh, and be sure to read jwilling.com/osx-animations before changing the frame using Core Animation. It's an excellent article!Truck
C
0

It is now 2023 and there have been some minor updates. .OnSetNeedsDisplay is now .onSetNeedsDisplay (note capitalisation) and the protocols for animatePresentation and animateDismissal are slightly different.

Here is a current version of Thomas' code:

import SwiftUI

class MacOSTransitionAnimator: NSObject, NSViewControllerPresentationAnimator {

func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) {

    let bottomVC = fromViewController
    let topVC = viewController

    // make sure the view has a CA layer for smooth animation
    topVC.view.wantsLayer = true

    // set redraw policy
    topVC.view.layerContentsRedrawPolicy = .onSetNeedsDisplay

    // start out invisible
    topVC.view.alphaValue = 0

    // add view of presented viewcontroller
    bottomVC.view.addSubview(topVC.view)

    // adjust size
    topVC.view.frame = bottomVC.view.frame

    // Do some CoreAnimation stuff to present view
    NSAnimationContext.runAnimationGroup({ (context) -> Void in

        // fade duration
        context.duration = 2
        // animate to alpha 1
        topVC.view.animator().alphaValue = 1

    }, completionHandler: nil)

}

func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) {

    let bottomVC = fromViewController
    let topVC = viewController

    // make sure the view has a CA layer for smooth animation
    topVC.view.wantsLayer = true

    // set redraw policy
    topVC.view.layerContentsRedrawPolicy = .onSetNeedsDisplay

    // Do some CoreAnimation stuff to present view
    NSAnimationContext.runAnimationGroup({ (context) -> Void in

        // fade duration
        context.duration = 2
        // animate view to alpha 0
        topVC.view.animator().alphaValue = 0

    }, completionHandler: {

        // remove view
        topVC.view.removeFromSuperview()
    })

}

}

Capers answered 2/5 at 2:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.