Mikko Harju
Mikko Harju

Reputation: 163

UINavigationViewControllerDelegate with custom animations break default behavior?

I've been trying to make UINavigationViewControllerDelegate to implement the required methods for custom transitions. They are working as expected and I am also able to add interactive transitions into the mix as well.

The problem is that when I implement those methods I lose the default "swipe right to go back" support from normal navigation transitions completely. I gain those back by setting the navigationController.delegate = nil before entering the view controllers I want to have the normal transitions. This means I'll have to store the actual old delegate and re-set it when I return from the view.

The documentation states that one should return nil from the navigationController:interactionControllerForAnimationController: and navigationController:animationControllerForOperation:fromViewController:toViewController: which is exactly what I am doing:

- (id<UIViewControllerAnimatedTransitioning>)navigationController:
        (UINavigationController *)navigationController 
    animationControllerForOperation:(UINavigationControllerOperation)operation 
    fromViewController:(UIViewController *)fromVC 
    toViewController:(UIViewController *)toVC
{
    if([fromVC isKindOfClass:[MainViewController class]] &&
       [toVC isKindOfClass:[MenuViewController class]]) {
        self.menuTransition.isPresentation = YES;
        return self.menuTransition;
    } else if([toVC isKindOfClass:[MainViewController class]] &&
              [fromVC isKindOfClass:[MenuViewController class]]){
        self.menuTransition.isPresentation = NO;
        return self.menuTransition;
    }
    return nil;
}

- (id<UIViewControllerInteractiveTransitioning>) navigationController 
        (UINavigationController *)navigationController 
    interactionControllerForAnimationController:
        (id<UIViewControllerAnimatedTransitioning>)animationController
{
    MenuTransition *t = (MenuTransition*)animationController;

    if(![t isPresentation] && [t isInteractive]) {
        return self.menuTransition;
    }
    return nil;
}

What else could be wrong here?

Upvotes: 0

Views: 562

Answers (2)

Паша Матюхин
Паша Матюхин

Reputation: 1153

When push viewController2 in viewController1 set navigationController.delegate = nil , then in your pushed view controller interactive pop gesture will be default and work perfectly, and when you pop viewController2 add this code to viewController1

override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        navigationController?.delegate = navigationController as? UINavigationControllerDelegate
}

Upvotes: 0

Jared Messenger
Jared Messenger

Reputation: 1236

The docs do give the impression that returning nil would work, but I found that the gesture recognizers were conflicting. Implementing gestureRecognizerShouldBegin fixed the issue for me.

*Note, this was written in swift but should be easy enough to convert to obj-c. This is a Navigation Controller SubClass with the UIGestureRecognizerDelegate Protocol

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
        self.interactivePopGestureRecognizer.delegate = self

        self.transitionGesture = UIPanGestureRecognizer(target: self, action: "handlePanGesture:")
        self.view.addGestureRecognizer(transitionGesture)
        self.transitionGesture!.delegate = self

    func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer!) -> Bool {
        if  self.transitionCoordinator()?.isAnimated() {
            return false
        }


        if self.viewControllers.count < 2 {
            return false
        }

        var currentVC: UIViewController? = self.viewControllers[self.viewControllers.count-1] as? UIViewController
        if let vc = currentVC as? MyCustomVC {
            if gestureRecognizer == self.transitionGesture {
                return true
            }
        } else if gestureRecognizer == self.interactivePopGestureRecognizer {
            return true
        }
        return false
    }

Upvotes: 2

Related Questions