Here is my code used to present a navigationViewController :
-(IBAction)showFilterView:(id)sender {
FilterViewController *vc=[self.storyboard instantiateViewControllerWithIdentifier:#"FilterViewController"];
UINavigationController *nvc=[[UINavigationController alloc] initWithRootViewController:vc];
CATransition *transition = [CATransition animation];
transition.duration = 0.35;
transition.timingFunction =
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromLeft;
UIView *containerView = self.view.window;
[containerView.layer addAnimation:transition forKey:nil];
[self.tabBarController presentViewController:nvc animated:NO completion:nil];
}
And here is my code to dismiss
-(IBAction)back:(id)sender {
CATransition *transition = [CATransition animation];
transition.duration = 0.35;
transition.timingFunction =
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromRight;
UIView *containerView = self.view.window;
[containerView.layer addAnimation:transition forKey:nil];
[[self.navigationController presentingViewController] dismissViewControllerAnimated:NO completion:nil];
}
Situation 1 --- Working well in landscape mode
Situation 2 --- Working well in portrait mode
Situation 3 --- Presenting in a portrait mode and dismissing in landscape mode not working properly(extra animation before displaying correct view)
Situation 4 ---Presenting in a landscape mode and dismissing in portrait mode not working properly(extra animation before displaying correct view)
The UIWindow layer has weird rotation properties and any animations you perform aren't guaranteed to correctly detect orientation (and vary with different iOS versions). The easiest way to do what you're trying to is with a custom presentation animation. This is a good writeup of how to do it.
I am using the old (pre-iOS7) push/pop animation by using the method described here:
#implementation UINavigationController (Retro)
- (void)pushViewControllerRetro:(UIViewController *)viewController {
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[self.view.layer addAnimation:transition forKey:nil];
[self pushViewController:viewController animated:NO];
}
- (void)popViewControllerRetro {
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[self.view.layer addAnimation:transition forKey:nil];
[self popViewControllerAnimated:NO];
}
#end
My problem is that iOS7 seems to fade the UINavigationBar of the previous view controller when pushing a new view controller. Normally this looks fine because iOS 7 is dragging the views on top of each other. But when I am using the pre-iOS7 animation it gives me a short flash, because the navigation bar fades while the new view it getting pushed in from the right side.
Is there a way to disable the fade animation on the navigation bar?
I have a line of viewControllers set in line. The idea is to go through a process of questions etc. If i was to use the already set up way of changing view controller (through button - modal), i would have no problem with memory. I have tried it. However i need to change the views programmatically and not with buttons directly.
When i do this programmatically my memory usage just starts increasing as i go through the views, until eventually i get a Memory Warning and a crash.
To change the viewController i use custom UIStoryBoardSegue and also methods in the viewController files.
Here is how i do it:
Method in View Controller:
-(void)changeViewController
{
CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.timingFunction =[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[self.view.window.layer addAnimation:transition forKey:nil];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"enterInfoSecondViewController"];
[[[[[UIApplication sharedApplication]delegate]window]rootViewController]presentViewController:vc animated:NO completion:nil];
// [self dismissViewControllerAnimated:YES completion:nil];
//[self presentViewController:vc animated:NO completion:nil];
// [self dismissViewControllerAnimated:NO completion:nil];
}
In custom Segue:
-(void)perform
{
UIViewController *srcViewController = (UIViewController *)self.sourceViewController;
UIViewController*destViewController = (UIViewController *)self.destinationViewController;
CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[srcViewController.view.window.layer addAnimation:transition forKey:nil];
[srcViewController presentViewController:destViewController animated:NO completion:nil];
}
......
Somewhere I do it with segue and somewhere with the top method.
What am i doing wrong? i need help please :) Thank you in advance.
If all you need is to trigger the segue programmatically,
why not use -performSegueWithIdentifier:sender: ?
I am trying to implement a 'Cover Horizontal' transition for my Storyboard's UIViewControllers. A simple slide right to left and back again. First I am surprised that this is not an option in Interface Builder. Doesn't everybody need this or am I missing something?
I created a Custom-Segue and added a Sliding Transition.
#import "SlideLeftCustomSegue.h"
#implementation SlideLeftCustomSegue
- (void)perform{
UIViewController *srcViewController = (UIViewController *) self.sourceViewController;
UIViewController *destViewController = (UIViewController *) self.destinationViewController;
CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[srcViewController.view.window.layer addAnimation:transition forKey:nil];
[srcViewController presentViewController:destViewController animated:NO completion:nil];
}
#end
That all works fine in the push direction but how do I get the same effect for the dismiss? It all seems a bit difficult for a very simple transition. Again I feel I am missing something.....
Any help would be great.
I'm nearly a newbie to Xcode 4.
There's a way to add to a segue a custom transition animation that it is not among the four presented by the Interface Builder in the storyboard management?
Specifically, i want an animation similar to the normal "cover vertical", but horizontal. I want the a view to pass to another sliding from left to right (or right to left) instead that from up to bottom as it happens in the "cover vertical" transition.
I tried with the swipe gesture but no fortune: even that is transitioning from up to bottom and anyway, i don't understand why the defaul transition is from up to bottom when the default transition of all the app usually is right to left or left to right, especially in the case you do swipe...
I tried also a programatically way but no fortune even in this case, using this code:
#import "JHCustomSegue.h"
#implementation JHCustomSegue
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView transitionWithView:src.navigationController.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[src presentModalViewController:dst animated:NO];
}
completion:NULL];
}
#end
In the interface builder i defined this class as the class of my segue. Using breakpoint, i saw it enter the function perfom but... don't perform!
I've blocked the app in portrait mode (don't know if it's a problem). I tried to run the application on a real ipad and on a simulated iphone. Same Problem.
You can use CATransition within a custom Segue to achieve left to right transition. Add this #import "QuartzCore/QuartzCore.h" to your custom Segue
-(void)perform {
__block UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
__block UIViewController *destinationController = (UIViewController*)[self destinationViewController];
CATransition* transition = [CATransition animation];
transition.duration = .25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[sourceViewController.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[sourceViewController.navigationController pushViewController:destinationController animated:NO];
}
Based on Zakir Hyder's submission, here is the same functionality translated to Swift:
override func perform() {
var sourceViewController = self.sourceViewController as UIViewController
var destinationViewController = self.destinationViewController as UIViewController
var transition: CATransition = CATransition()
transition.duration = 0.25
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
sourceViewController.navigationController?.view.layer.addAnimation(transition, forKey: "kCATransition")
sourceViewController.navigationController?.pushViewController(destinationViewController, animated: false)
}
Here is the working code for custom seque when not using navigation controller.
-(void)perform
{
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
CATransition* transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromRight; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[destinationController.view.layer addAnimation:transition forKey:kCATransition];
[sourceViewController presentViewController:destinationController animated:NO completion:nil];
}
Check out this Example on Github:
https://github.com/itinance/iOSCustomSegue
It uses a custom segue from right to left in an example app explicitly without UINavigationController as the thread opener where asking for.
The Code in the answer of Sahil didn't work for me at iOS 8. So i had to investigate a little bit more on this issue.
'UIView animateWithDuration' works on iOS 8, while 'destinationController.view.layer addAnimation:transition' does nothing in combination with presentViewController.
I tried using Segue to do the same effect too, but without success. Instead, I used a workaround:
// get the view that's currently showing
UIView *currentView = self.view;
// get the the underlying UIWindow, or the view containing the current view
UIView *theWindow = [currentView superview];
UIView *newView = aTwoViewController.view;
// remove the current view and replace with myView1
[currentView removeFromSuperview];
[theWindow addSubview:newView];
// set up an animation for the transition between the views
CATransition *animation = [CATransition animation];
[animation setDuration:0.5];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[theWindow layer] addAnimation:animation forKey:#"SwitchToView2"];
You can download the sample project here. Cheers!