UINavigationController custom transition removes view underneath - ios

I'm implementing my own UINavigationController transition using:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC{
return self;
}
What happens though, the pushing viewController.view disappears as soon as the transition finishes. I present views using
[self.navigationController pushViewController:pushedViewController animated:YES];
Is there a way to tell TransitionCoordinator not to delete the presenting controller's view when I push them using UINavigationController? Do I really need to implement my own ContainerView with all the logic?

I finished up making my own ContainerViewController. Now I have total control over views' lifespan.

Related

Objective-C: UINavigationBar not update when go back to root controller

this is my question. I have three View Controllers (VC1, VC2 and VC3). Every View Controller inherited from UINavigationControllerDelegate and I delegate my navigation controller into the viewWillAppear method in this way:
self.navigationController.delegate = self;
And the only UINavigationControllerDelegate method that I use is for transition:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
if (operation == UINavigationControllerOperationPush || operation == UINavigationControllerOperationPop) {
myTransitionController *transitionController = [[myTransitionController alloc] init];
return transitionController;
}else{
return nil;
}
}
My problem is this: when I walk from VC1 to VC2 and into this controller trigger a NSNotification, I execute popViewControllerAnimated to go back the previous View Controller (VC1). This is the code:
- (void) backToRoot: (id) sender{
[self.navigationController popViewControllerAnimated:YES];
}
and the UINavigationBar show correctly its appearance (UINavigationBar without back button). Then, when I walk from VC1 to VC2 until VC3, and programatically go back until VC1 with popToRootViewController, the transition of the views (VC3-VC2-VC1) it works perfectly, but the UINavigationBar appearance not update and it shows with back button in the VC1 (which is the root View Controller). The method in the VC3 that I implemented is this:
- (void) goToRoot{
[self.navigationController popToRootViewControllerAnimated:YES];
}
I have tried with a double call of popViewControllerAnimated, I added in viewWillAppear and viewDidAppear method into VC2 and It not works neither. Anyone have idea what happens?
According to the documentation the func Pops all the view controllers on the stack except the root view controller and updates the display but I can't figure out the problem. You can try with unwind segue, is really simple.
What are Unwind segues for and how do you use them?

Animating to View Controller that is a UINavigationController

I'm trying to use transitioningDelegate to apply custom animations when transitioning from VC1 to VC2. This, in general, works but now a need a navigation bar in VC2. So, I embedded VC2 in a navigation controller which gets me my navigation bar but now the methods for doing the animation (via transitioningDelegate) are not called. I can't use the animation for navigation controllers because VC2 is essentially the root of my navigation controller so, subsequent push/pop can be animated but not the first one.
Is there anything special needed when animating to navigation controller?
This is in Xcode 7, iOS 9 and using Storyboards.
Please help.
PS: Merry Christmas!
So first of all, to your question, it seems like in your animation code, you should use the navigation controller object instead of VC2 to be part of the animation, not VC2, because you embed it, otherwise, you won't have your VC2 in a navigation stack.
From my experience, transitioningDelegate is about presenting a view controller with custom modal presentation type. It has limitations if you want advanced view controllers transitions, because not every scenario is suitable for 'presenting(modal)' a controller, such as I got a login view controller, and presenting your home view controller on a login controller is kind of limited.
I used to create a container controller, which is the parent of all the others controllers, so I can use
- (void)transitionFromViewController:(UIViewController *)fromViewController
toViewController:(UIViewController *)toViewController
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion
to gain the ultimate control of the transit and animations among child view controllers. It has nothing to do with modal, navigation controller, they just have to be in a common parent view controller, like appDelegate.window.rootViewController
Let's say we have a parent controller named parentViewController
We manually add VC1 and navigationController(which embeds VC2) into parentViewController and transit them with animations you like:
[parentViewController addChildViewController:VC1];
[parentViewController addChildViewController:navigationController];
[VC1 willMoveToParentViewController:nil];
[parentViewController transitionFromViewController:VC1
toViewController:navigationController
duration:duration
options:options
animations:^{
// your animation code, or do nothing and use UIViewAnimationOptionTransitionCrossDissolve as options to have a default animation
} completion:^(BOOL finished) {
[navigationController didMoveToParentViewController:parentViewController];
[VC1 removeFromParentViewController];
}];
note
[VC1 willMoveToParentViewController:nil];
[navigationController didMoveToParentViewController:parentViewController];
[VC1 removeFromParentViewController];
They are essential to be called.

Call custom transition animator using a programmatically created segue IOS

the project I am working on needs to have a custom transition between two view controllers. I have setup and implemented UIViewControllerTransitioningDelegate by overriding the method like:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
//Creation of animation
id<UIViewControllerAnimatedTransitioning> animationController;
MyAnimator *animator = [[MyAnimator alloc] init];
animator.appearing = YES;
animationController = animator;
return animator
}
And I have setup MyAnimator subclass to correctly implement UIViewControllerAnimatedTransitioning by overriding the method:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
//custom transition animation
}
The segue which I using to trigger this animation transition is created and called programmatically, like:
UIStoryboardSegue *segue = [[UIStoryboardSegue alloc] initWithIdentifier:#"showCardDetail" source:self destination:vc];
[self prepareForSegue:segue sender:self];
[segue perform];
Reason of creating segue programmatically: I have from(transition from) and to(transition to) view controllers in separate storyboards.
Problem / Question:
I have seen many examples, all handle the custom transition using a storyboard segue like:
[self performSegueWithIdentifier:#"storyboardSegue-id" sender:self]
How should i define in the method -perform for segue created programmatically above so that the custom transition takes place.
You don't need to create a custom segue to do what you're trying to do. In fact, since you have your 2 controllers in separate storyboards, you shouldn't use a segue at all. Just instantiate your destination view controller, and use pushViewController:animated: to initiate the transition. Your first view controller should be the delegate of the navigation controller, so the delegate method you show at the top of your question gets called.
In navigationControllerAnimationControllerForOperation:fromViewController:toViewController: you can adjust source and destination viewControllers and based on this types you will see desired animation. You do not need to use prepareForSegue: here.

Custom transition for push and standard transition for pop

I have a View Controller that has a custom push transition when a table cell is tapped and performs the standard pop transition when the back bar button item is tapped. The problem is when I try to go to the same view controller from the previous controller, the app crashes. Below is the UINavigationControllerDelegatefunction I'm implementing:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
return (operation == UINavigationControllerOperationPush ? animator : nil);
}
Any clue is appreciated!
Thanks in advance.
I had a problem, where the NavigationController's delegate was set to a view controller that had been deallocated, which caused a crash in [UINavigationController _customTransitionController:].
Especially when using unwind segues, it does NOT seem that any intermediate view controllers receive a viewWillDisappear callback before getting deallocated. The remedy here is to implement the following in the destination unwind view controller:
-(IBAction)unwindSegue:(UIStoryboardSegue*)segue{
self.navigationController.delegate = nil;
}

Replicating dismissViewController animation

I have a view controller that I am trying to pop. The animation that I would like to use is the same as the animation that would show when dismissViewController would be called. What would be the best way to replicate this for popToRootViewController. I know how to create custom view controller animations, but I was wondering what will be the best way to do this?
To control the animation that happens when you call popToRootViewControler, you'll just need to set your navigation controller's delegate and implement the UINavigationControllerDelegate method:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
From there, you'll return self or any object where you can implement the UIViewControllerAnimatedTransitioning method:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext

Resources