How to implement UIView transition - iphone

I have an app which has a start screen with a start button on it. If you tap that button the view changes and a new view appears, let's call that main view.
The way I implemented it is one view controller per view. Now that I want to add transition animations this implementation causes problems. For example, I want to use the following code:
[UIView transitionFromView:startView toView: mainView duration: 2.0
options: UIViewAnimationOptionTransitionCurlDown completion: NULL];
But this doesn't do anything. Reading the documentation suggests that this only works if the view controller doesn't change. The documentation doesn't have any examples of a curl down transition where the view controllers change so I'm not sure what to do.
When I started writing the app I read the guidelines and they suggested that having one view controller per view is the correct way of doing what I'm doing.
Now what is the correct way to implement a view transition when the view controller changes too? Many thanks for your help!
Edit: I am looking for a solution where the first view controller is destroyed.

It was proposed that you effectively create a view controller, use its view, but then disregard the controller itself. This is not advised. In iOS you want to keep your view controller hierarchy synchronized with your view hierarchy. Any techniques like the one proposed are therefore problematic. (WWDC 2011 session 102, while on a different topic, view controller containment, has a lengthy discussion of the importance of keeping these two hierarchies synchronized.)
The most obvious problem is that certain events, notably rotation events, are not going to transmitted successfully to your new controller and you can get some very strange results. It's also not clear with your code above what happens with the old view that you removed, how you would transition back, how you'd clean up the now unnecessary game controller, what would happen on didReceiveMemoryWarning if you were in the game controller, etc. This just seems to introduce a ton a problems.
The easiest solution is apply standard pushViewController and/or presentViewController calls to go from one view to another, and just animate those transitions. If you have questions about either of those methods, or how to animate within the context of those methods, let me know.

By the way, the root of your question was how to transition between view controllers. Here is a old collection of transitions (some for push transitions, some for modal transition) that I was once playing around with. Maybe there's something here that you could use?
- (void)transitionToNewController
{
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
#if TRANSITIONTYPE == 1
// pushViewController with push/slide from right via CATransition
CATransition* transition = [CATransition animation];
transition.duration = 0.3;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController pushViewController:controller animated:NO];
#endif
#if TRANSITIONTYPE == 2
// pushViewController with flip using UIView begin/commitAnimations
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController pushViewController:controller animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[UIView commitAnimations];
#endif
#if TRANSITIONTYPE == 3
// pushViewController with flip using animation block
[UIView animateWithDuration:0.5
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self.navigationController pushViewController:controller animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}
completion:nil];
#endif
#if TRANSITIONTYPE == 4
// pushViewController with fade via CATransition
CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController pushViewController:controller animated:NO];
#endif
#if TRANSITIONTYPE == 5
// pushViewController with fade via animation block
controller.view.alpha = 0.0f;
[UIView animateWithDuration:0.5
animations:^{
self.view.alpha = 0.0f;
controller.view.alpha = 1.0f;
}
completion:^(BOOL finished){
[self.navigationController pushViewController:controller animated:NO];
self.view.alpha = 1.0f; // reset the src alpha so it's there when you pop your view controller off
}];
#endif
#if TRANSITIONTYPE == 6
// pushViewController Flip using UIView begin/commitAnimations
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController pushViewController:controller animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[self.self navigationController].view cache:NO];
[UIView commitAnimations];
#endif
#if TRANSITIONTYPE == 7
// pushViewController animation using CGAffine scale to look like we're zooming into the new view
[self.view addSubview:controller.view];
[controller.view setFrame:self.view.window.frame];
[controller.view setTransform:CGAffineTransformMakeScale(0.5,0.5)];
[controller.view setAlpha:1.0];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
[controller.view setTransform:CGAffineTransformMakeScale(1.0,1.0)];
[controller.view setAlpha:1.0];
}
completion:^(BOOL finished){
[controller.view removeFromSuperview];
[self.navigationController pushViewController:controller animated:NO];
}];
#endif
#if TRANSITIONTYPE == 8
// presentViewController animation with slide from right by using CGAffineTransform
self.view.transform = CGAffineTransformMakeTranslation(0, 0);
controller.view.transform = CGAffineTransformMakeTranslation(self.view.frame.size.width, 0);
[self.view addSubview:controller.view];
[UIView animateWithDuration:4.0
animations:^{
// [self presentViewController:controller animated:NO completion:nil];
self.view.transform = CGAffineTransformMakeTranslation(self.view.frame.size.width, 0);
controller.view.transform = CGAffineTransformMakeTranslation(0, 0);
}
completion:^(BOOL finished){
[controller.view removeFromSuperview];
[self presentViewController:controller animated:NO completion:nil];
}
];
#endif
#if TRANSITIONTYPE == 9
// presentViewController animation with slide from right by just animating frames
float width = self.navigationController.view.frame.size.width;
CGPoint right = controller.view.center;
right.x += width;
controller.view.center = right;
[self.navigationController.view addSubview:controller.view];
[UIView animateWithDuration:0.5
animations:^{
CGPoint left = self.navigationController.view.center;
left.x -= width;
self.navigationController.view.center = left;
}
completion:^(BOOL finished){
[controller.view removeFromSuperview];
[self presentViewController:controller animated:NO completion:nil];
}
];
#endif
#if TRANSITIONTYPE == 10
// presentViewController animation with flipfromright
[UIView animateWithDuration:4.0
delay:0.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[self.view addSubview:controller.view];
}
completion:^(BOOL finished){
[controller.view removeFromSuperview];
[self presentViewController:controller animated:NO completion:nil];
}];
#endif
#if TRANSITIONTYPE == 11
// presentViewController with flip using UIView begin/commitAnimations
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self presentViewController:controller animated:NO completion:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
[UIView commitAnimations];
#endif
#if TRANSITIONTYPE == 13
// pushViewController with flip using animation block with transitionWithView
controller.view.frame = self.view.window.frame;
[UIView transitionWithView:self.view.superview
duration:1.0
options:UIViewAnimationTransitionFlipFromRight
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self.view.superview addSubview:controller.view];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}
completion:^(BOOL finished){
[self.navigationController pushViewController:controller
animated:NO];
}];
#endif
}

Okey-doke, I found a neat way to achieve exactly what I want. This code, added in the method where I exchange the old view controller and view with the new one, works great:
GameViewController *game = [[GameViewController alloc] init];
UIView *currentView = [currentViewController view];
// remove the current view and replace with myView1
[currentView removeFromSuperview];
// set up an animation for the transition between the views
CATransition *animation = [CATransition animation];
[animation setDuration:0.5];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromBottom];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[window layer] addAnimation:animation forKey:#"SwitchToView1"];
[self setCurrentViewController: game];
[window addSubview:[currentViewController view]];
[game release];
Many thanks to HERE!!

Related

Transitions between UIView in the same UIViewController

I want to transit from UIView to another in the UIViewController when I press a button
I write this code:
- (IBAction)changeView:(id)sender {
CATransition* transition = [CATransition animation];
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
transition.duration = 1.0f;
transition.type = #"cube";
transition.subtype = #"fromTop";
[self.view1.layer removeAllAnimations];
[self.view1.layer addAnimation:transition forKey:kCATransition];
}
this code will transit the view1(UIview) to itself. how can I make it to transit to another UIView (e.g. view2). also where can I put the another UIview (view2) in the storyboard
Have you try like this?
self.view1.alpha = 0.0;
[UIView beginAnimations:#"flip" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView setAnimationDuration:1.0f];
self.view2.alpha = 1.0;
[UIView commitAnimations];
Have a look at this code snippet it's much more elegant. Also checkout Apple's documentation for more fancy UIViewAnimationOptions
- (IBAction)changeView:(id)sender
{
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
//Remove View-1 from the main view
[view1 removeFromSuperView];
//Add the new view to your current view
[self.view addSubView:view2];
} completion:^(BOOL finished) {
//Once animation is complete
}];
}
Ensure that the two views are a strong property of your view controller.
If you have two UIView for example take firstView and secondView and add it to UIViewController on same rect. and set hiddden property to secondView.
-(IBAction)flipFirstViewToSecondView{
secondView.hidden= NO;
[UIView transitionWithView:firstView duration:1.0f options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
[UIView transitionWithView:secondView duration:1.0f options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
} completion:^(BOOL finished) {
secondView.hidden = NO;
firstView.hidden = YES;
}];
} completion:^(BOOL finished) {
}];
}
Thanks. just let me know if you have any problem to integrate it.

pushViewController without title animation

I push Viewcontroller using this code:
if (! self.infoViewController) {
self.infoViewController = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
}
[UIView animateWithDuration:0.7f
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self.navigationController pushViewController:self.infoViewController animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}];
Is it possible to disable navigationBar title animation? It's slide from left during animation.
Push your ViewController without animation like this:
if (! self.infoViewController) {
self.infoViewController = [[InfoViewController alloc] initWithNibName:#"InfoViewController" bundle:nil];
}
[self.navigationController pushViewController:self.infoViewController animated:NO];
this will not animate ur pushing title. I hope this will helps u.
I'm sorry. Here is the answer:
[UIView animateWithDuration:0.7f
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}];
[self.navigationController pushViewController:self.infoViewController animated:NO];

ViewController transition

I have code:
ListViewController * listViewController = [[ListViewController alloc] initWithNibName:#"ListViewController" bundle:nil];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[self viewWillDisappear:YES];
[listViewController viewWillAppear:YES];
self.view.hidden = YES;
listViewController.view.hidden = NO;
[self viewDidDisappear:YES];
[listViewController viewDidAppear:YES];
[UIView commitAnimations];
But it does not works, and listViewController does not displayed( Please, somebody can tell me the solution of this problem?
Try something like:
UIViewAnimationOptions ops = UIViewAnimationOptionTransitionFlipFromRight;
NSArray *temp = [[NSBundle mainBundle] loadNibNamed:#"NameOfNib" owner:self options:nil];
UIView* newView = [[temp objectAtIndex:0] view];
[UIView transitionFromView:self.view toView:newView duration:1.5 options:ops completion:nil];
self.view = newView; //Lets you control the new view from the current controller (you might want to save a reference to the old one if you need to change back)
As meronix said, non-block based animation is discouraged by Apple for the newer iOS versions. The above method is the "approved" way to do it.
Just so you know, the viewWillAppear, viewDidDisappear, and similar methods aren't methods that YOU call to make the view do things. They're called automatically when these things happen.
Your code had a few misunderstandings; I've commented on them below
//This looks fine (depending on what is in the nib)
ListViewController * listViewController = [[ListViewController alloc] initWithNibName:#"ListViewController" bundle:nil];
//Normally I use these to move things around, not change the view
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[self viewWillDisappear:YES]; //These two methods aren't things that you call
[listViewController viewWillAppear:YES];
self.view.hidden = YES; //If you're flipping or otherwise moving a view out of
listViewController.view.hidden = NO; //sight then you don't need to hide/unhide views
[self viewDidDisappear:YES]; //Same as above, you don't call these
[listViewController viewDidAppear:YES];
[UIView commitAnimations];
Remove unnecessary code and just write this ...
ListViewController * listViewController = [[ListViewController alloc] initWithNibName:#"ListViewController" bundle:nil];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[self.view addSubview:listViewController.view];
[UIView commitAnimations];
it cannot work!
you just create and allocate a UIViewController, but never push it on any stacks, or add its view to a visible view.
when you set listViewController.view.hidden to no, you are not magically showing it on screen: you need to add its view to a view (or window) which is already on screen...
ps beginAnimation is deprecated: use blocks animation instead...

UINavigationController: pop view controller in the opposite direction

I'm trying to call [[self navigationController] popViewControllerAnimated:YES] but making the animation slide right to left instead of left to right. Any easy way to do this? I want to return to the previous view. Any help is appreciated. Thanks!
This is how one can pop view controller in opposite direction. Its working for me 100%
CATransition *transition = [CATransition animation];
transition.duration = 0.45;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
transition.type = kCATransitionFromRight;
[transition setType:kCATransitionPush];
transition.subtype = kCATransitionFromRight;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController popViewControllerAnimated:NO];
It is possible, look at the following code I used a while back and try to make it work for yourself. Yu only need to change the setAnimationTransition
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
[UIView commitAnimations];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:0.375];
[self.navigationController popViewControllerAnimated:NO];
[UIView commitAnimations];
There are a few different kind of default animations to use, apples site says this kind of animations are possible:
typedef enum {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
} UIViewAnimationTransition;
So in your case you would want to use the following:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController popViewControllerAnimated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[UIView commitAnimations];

How do i do a flip animation on pop view controller?

I have a flip animation which goes like this:
Picker *picker = [[Picker alloc] init];
[self.navigationController pushViewController:picker animated:NO];
[UIView animateWithDuration:0.5
animations:^{
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}
completion:^(BOOL finished){
}];
[picker release];
This works perfectly. But when i want to do popViewController to get back, like this:
[self.navigationController popViewControllerAnimated:NO];
[UIView animateWithDuration:0.5
animations:^{
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}
completion:^(BOOL finished){
}];
But this doesn't work, just goes back to the view without animating.
Have you tried calling popViewControllerAnimated after the animation ends?
Put the popViewController call inside your completion block, so it animates first and then pops.