0
votes

In my work on an iOS multi-screen App, I am trying to get my first custom animated transaction to work. Instead of using standard animations when presenting a screen modal and fullscreen, I want to have a horizontal slide in animation.

I have made this work by overriding perform in UIStoryboardSegue, and make the animation and transaction be performed from here.

Overall, it works, except from one case, which is when a navigation controller embeds a view.

In that case, I have followed a tutorial showing precisely how custom transaction is achieved by implementing the UINavigationControllerDelegate protocol for the particular navigation controller.

import Foundation
import UIKit

class AnimatedNavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {

        super.viewDidLoad()
        delegate = self
    }

    func navigationController(_ navigationController: UINavigationController,
                              animationControllerFor operation: UINavigationController.Operation,
                              from fromVC: UIViewController,
                              to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

        return NavigationControllerTransition()
    }
}

Unfortunately the delegate, which should return an animation object:

navigationController(_:animationControllerFor:from:to:)

is never called, and that is my primary problem.

In the tutorial mentioned, a button is used to perform a call to the navigation controller that pushes the destination view with animation set to true:

navigationController.pushViewController(view, animated:true)

In my case, I suspect that the problem is that the navigation controller pushes the view without having the animation parameter set to true, and that explains why the transaction delegate is never called.

(a confirmation off this theory will of course help a bit).

Consequently, I have tried to implement a custom segue that presents the view by calling the push function with animation set to true.

Sadly, I have not been able to get this to work.

When the navigationController.pushViewController(view, animated:true) is called, it raises an exception saying that view has already been pushed.

I have tried a lot without any luck. Code looks like this:

class NavigationControllerSegue: UIStoryboardSegue {

    override func perform() {

        let navigationController = self.destination as! UINavigationController

        let view = navigationController.viewControllers.first!

        navigationController.pushViewController(view, animated: true)
    }
}
1

1 Answers

0
votes

Hey first of all we are talking about two different animations... the first "UIStoryboardSegue" creates a custom subclass UIStoryboardSegue, and this is assigned to the following in question set an id to the following, below just call from the 'ViewController' a self.performSegue(withIdentifier: "YOUR-ID", sender: nil), Example of the subclass UIStoryboardSegue:

import UIKit
// Example =>
class ScaleSegue: UIStoryboardSegue {

    override func perform() {
        self.scale()
    }

    func scale() {
        let toViewController = self.destination 
        let fromViewController = self.source

        let containerView = fromViewController.view.superview
        let originalCenter = fromViewController.view.center

        //let originalCenter = self.posizioneClick

        toViewController.view.transform = CGAffineTransform.init(scaleX: 0.05, y: 0.05)
        toViewController.view.center = originalCenter

        containerView?.addSubview(toViewController.view)

        UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseInOut, animations: {
            toViewController.view.transform = CGAffineTransform.identity
        }, completion: { success in
            fromViewController.present(toViewController, animated: false, completion: nil)
        })
    }

}

Now, you have to create a segue from storyboard and set as custom class of the segue from the AttributeInspector:

Screen-Storyboard-example

Now to use this you just need to call from the view controller => self.performSegue(withIdentifier: "segue1", sender: nil). Different is the way to implement Transition with UIViewControllerTransitioningDelegate. If you need to let me know, I can give you examples using this technique too, so long.