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!
Related
I have subclassed UIStoryboardSegue to create a Left to Right Segue. The segue works, however, there is a black vertical bar or background that is momentarily visible between the two View Controllers that mars the effect. (I want the segue to look like a normal right to left show segue but in the opposite direction). Does anyone know what could be causing this or how to get rid of it? Here is my code:
#import "customSegue.h"
#import "QuartzCore/QuartzCore.h"
#implementation customSegue
-(void)perform {
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
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];
}
#end
Edit:
I thought I would collect some the suggested fixes I have found although none are working for me.
Set the background color of the presenting view controller to white
Set self.definesPresentationContext = YES; on the presenting view controller or check "Defines Context" for the VC in storyboard from accepted answer here.
Specify the context as follows:
UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
UIViewController *destinationController = (UIViewController*)[self destinationViewController]
[sourceViewController presentViewController:destinationController animated:NO completion:nil];
from accepted answer here.
What you're seeing is the view's changing opacity near the beginning and end of the animation, so the "black bar" you're seeing is actually the backing window. While it might not be perfect, a quick fix is to change the background color of your window to match the background color of your destination view controller (then set it back after the transition completes if needed).
Here's your code example with the modifications necessary:
-(void)perform {
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
CATransition* transition = [CATransition animation];
CGFloat animationDuration = 0.25f;
transition.duration = animationDuration;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
transition.fillMode = kCAFillModeForwards;
[sourceViewController.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
// hold onto the previous window background color
UIColor *previousWindowBackgroundColor = sourceViewController.view.window.backgroundColor;
// switch the window background color to match the destinationController's background color temporarily
sourceViewController.view.window.backgroundColor = destinationController.view.backgroundColor;
// do the transition
[sourceViewController.navigationController pushViewController:destinationController animated:NO];
// switch the window color back after the transition duration from above
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(animationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// make sure we still have a handle on the destination controller
if (destinationController) {
destinationController.view.window.backgroundColor = previousWindowBackgroundColor;
}
});
}
Here's an example of the transition slowed down to 2seconds:
Slowed down transition
And the animation at 0.25 as you have it in your code:
Your speed transition
I am trying to replicate the following segue animation as seen in Secret where it bounces on the bottom of the screen. I have searched the internet but can't find anything to help me.
I am looking for the segue animation to dropdown from the top and bounce on the bottom of the screen.
Currently I have this but it doesn't bounce.
- (void)perform {
UIViewController *srcViewController = (UIViewController *) self.sourceViewController;
UIViewController *destViewController = (UIViewController *) self.destinationViewController;
CATransition *transition = [CATransition animation];
transition.duration = 0.4;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromBottom;
[srcViewController.view.window.layer addAnimation:transition forKey:nil];
[srcViewController presentViewController:destViewController animated:NO completion:nil];
}
If it helps I use the POP animation engine.
You need a custom transition using UIKit Dynamics to perform the animation.
This is mouli, I'm implementing a custom segue for pushing (with animation) from firstview to second view, its work fine. but iam not getting back from secondview to firstview with same animation. Here the first screen appears with out animation. please give some suggestion. Thanks in advance. following is my code for push from first to second.
UIViewController *sourceViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
NSLog(#"%#",sourceViewController);
sourceViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
NSLog(#"%#",destinationController);
CATransition* transition = [CATransition animation];
transition.duration = 0.6;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush; //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];
Do the dismiss in opposite way, since your are doing a custom animation other that the provided one, it doesn't remember the animation of presentation. So while you are dismissing you need to apply the opposite custom animation too.
I would suggest you to create a Category for animations and use them in the whole project easily..
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 have to 4 scene on my storyboard and everything works great, but right now I have a modal style with transition cover vertical. I want to have modal style but with a horizontal cover transition.
I change from scene to scene with a round rect button because my scenes does not have a navigation bar (because I don't need it).
I found a tutorial and I create a new class to override the perform method.
Here is my implementation file with the perfom method.
#import "JHCustomSegue.h"
#import "QuartzCore/QuartzCore.h"
#implementation JHCustomSegue
- (void) perform {
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
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 = kCATransitionFromRight; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[sourceViewController.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[sourceViewController.navigationController pushViewController:destinationController animated:NO];
}
#end
But the transition doesn't work I can chance to any of my scene I always stay in the first screen.
What I'm doing wrong, because the example works very well but they use a navigation bar.
Thanks in advance for your help.