I have a View that has a UIWebView, and an OptionsPane (Custom UIViewController with Custom view).
I want when the view is shown, for the options pane (located on the top of the main view) to FLIP into place. I am using the code, and I am getting a strange result.
The FIRST time the view is shown, the options pane seems to already be visible... When I hit BACK on my navController, and pull up the View again, the animation works perfectly.
Can anyone shed some light on this topic?
- (void)viewDidLoad {
[super viewDidLoad];
optionsPane=[[OptionsPaneController alloc] initWithNibName:@"OptionsPane" bundle:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[optionsPane.view removeFromSuperview];
[self checkOptionsVisible];
}
-(void)checkOptionsVisible{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[optionsPane view] cache:YES];
[[self view] addSubview:[optionsPane view]];
[theWebView setFrame:CGRectMake(0,87,320,230)];
[[optionsPane view] setFrame:CGRectMake(0,0,320,87)];
[UIView commitAnimations];
}
If I understand what your explaining, I had a very similar problem the other day.
What happening on the first load is that viewDidLoad fires first. loading the nib file takes a bit more time than it takes for the viewWillAppear to fire itself.
What we're getting is a nib loads after the viewWillApper already retired.
On any load after that, the viewDidLoad will not fire, letting the viewWillAppear to do its loyal flipping job.
What to do?
First, try to change your code to use "viewDidAppear". That should help, but you have to see if it looks good.
Another option (ugly one, I know) is to have a call to checkOptionsVisible on the viewDidLoad too.
If non of that help, I would consider a timer as a hack - if the requirements allow it.
I hope that make you closer to solve the problem.
Hmm, I don't think the viewWillAppear message is getting sent the first time. There are two things that I read in the SDK. You should call super inside that message and there is a big warning that may apply to your first time:
Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.
Ultimately, I would run through the debugger and make sure that viewWillAppear message is being sent when you think it is.
Updated for your situation:
Instead have four views:
A backing view
The main View
The back view (options pane) 100 pixels
The front view (blank view) 100 pixels
Add the main view to the backing view as normal.
Add the front view to the backing view where you would like the options pane to appear.
make sure the front and back view have the same frame.
Use the same code as below using the methods flip the front and back views.
Original Answer
You need 3 views:
A backing view
The front View
The back view
The backing view just holds the other 2 as they flip back and forth Below are the flipping methods. I place them both in backingViewController:
- (void)displayBack{
//parent controller is an ivar so the sub-view controllers know who their daddy is
backController.parentController = self;
[UIView beginAnimations:nil context:@"flipTransitionToBack"];
[UIView setAnimationDuration:1.2];
//note self.view IS the backing view
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
//remove the front view
[[frontController view] removeFromSuperview];
//add the back view view
[self.view addSubview:[backController view]];
[UIView commitAnimations];
//giving a heads up to the view that is about to come on screen
[backController viewWillAppear:YES];
}
- (void)displayFront{
[UIView beginAnimations:nil context:@"flipTransitionToFront"];
[UIView setAnimationDuration:1.2];
[UIView setAnimationDelegate:self];
//I'm interested in knowing this has happened
[UIView setAnimationDidStopSelector:@selector(flipAnimationDidEndWithID:finished:context:)];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
//remove back view
[[backController view] removeFromSuperview];
//add the front view
[self.view addSubview:[frontController view]];
[UIView commitAnimations];
}
The view property on a UIViewController is lazily-loaded -- even when you're init-ing with a nib as you are here, the view itself doesn't actually get instantiated until the first time the property is accessed.
It's hard to know exactly what's happening without seeing more code, but you may get the results you want if you access optionsPane.view in viewDidLoad (you don't need to do anything with it, just access the property to force loading).