Reputation: 1367
I'm looking to perform a segue to replace the window's root view controller by another view controller using a curl up animation.
The idea is that I have a SplashViewController
being displayed for a couple of seconds before transitioning (performSegueWithIdentifier:
) to the next one, LoginViewController
, using the curl up animation.
I've created a custom UIStoryboardSegue
class called AnimatedSegue
. Here is the code of the overridden perform
method:
- (void)perform
{
UIViewController *source = self.sourceViewController;
UIViewController *destination = self.destinationViewController;
UIWindow *window = source.view.window;
[UIView transitionFromView:source.view
toView:destination.view
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
completion:^(BOOL finished) {
[window setRootViewController:destination];
}];
}
It works fine except that in iOS 6 (apparently not in iOS 5) the viewWillAppear:
method is being called twice on the destination
view controller.
It seems that it's called a first time during the transition and second time when it executes [window setRootViewController:destination];
Note that I don't want to use a navigation controller. The SplashViewController
gets deallocated (as expected) once the transition is over.
Any ideas on how to fix my problem?
Upvotes: 8
Views: 2368
Reputation: 3091
If you really, really want to use transitionFromView:
the only thing I could find that works is to just create a screen shot of the source view controller, and animate that.
- (void)perform
{
UIViewController *source = self.sourceViewController;
UIViewController *destination = self.destinationViewController;
// Create screenshot for animation
UIGraphicsBeginImageContextWithOptions(source.view.bounds.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
[source.view.layer renderInContext:context];
UIImageView *screenShot = [[UIImageView alloc] initWithImage:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
// Put destination view controller and screen shot in place
UIWindow *window = source.view.window;
window.rootViewController = destination;
[window addSubview:screenShot];
[UIView transitionFromView:screenShot
toView:destination.view
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
completion:^(BOOL finished) {
}];
}
viewWillAppear:
and its ilk only get called once as expected.
Upvotes: 1
Reputation: 1367
Answering to my own question in case it can help someone else...
I ended up using Core Animation's CATransition
class to create the segue's animation instead of the UIView
's animation methods.
Here's how my new perform
method looks like:
- (void)perform
{
UIViewController *source = self.sourceViewController;
UIWindow *window = source.view.window;
CATransition *transition = [CATransition animation];
[transition setDuration:1.0];
[transition setDelegate:self];
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[transition setType:@"pageCurl"];
[transition setSubtype:kCATransitionFromBottom];
[window.layer addAnimation:transition forKey:kCATransition];
[window setRootViewController:self.destinationViewController];
}
Upvotes: 11
Reputation: 104082
I would probably do this in a different way, using 2 views and one controller, rather than 2 controllers with a custom segue. In your storyboard, just have a blank view for the controller, and add two xib files (of the view type) with the splash view and a main view. The splash view would be added as a subview of the controller's view in viewDidLoad, and then switched out using the same method you did:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.splashView = [[NSBundle mainBundle] loadNibNamed:@"SplashView" owner:self options:nil].lastObject;
[self.view addSubview:self.splashView];
[self performSelector:@selector(removeSplash) withObject:nil afterDelay:2];
}
-(void)removeSplash {
self.mainView = [[NSBundle mainBundle] loadNibNamed:@"MainView" owner:self options:nil].lastObject;
[UIView transitionFromView: self.splashView toView:self.mainView duration:.6 options:UIViewAnimationOptionTransitionCurlUp
completion:nil];
}
Upvotes: 2