How do I rotate only some views when working with a uinavigationcontroller as a tab of a uitabbarcon
- by maxpower
Here is a flow that I can not figure out how to work. ( when I state (working) it means that in that current state the rules for orientation for that view are working correctly)
First View: TableView on the stack of a UINavigationController that is a tab of UITabBarController.
TableView is only allowed to be portrait. (working)
When you rotate the TableView to landscape a modal comes up with a custom UIView that is like a coverflow (which i'll explain the problem there in a moment).
A Selection made on tableview pushes a UIScrollview on to the stack.
UIScrollView is allowed all orientations. (working)
When UIScrollView is in landscape mode and the user hits back they are taken to the custom UIView that is like the coverflow and only allows landscape.
The problem is here. Because the UIScrollView allows full rotation it permitted the TableView to rotate as well to landscape.
I have a method attached to a notification "UIDeviceOrientationDidChangeNotification" that checks to see if the custom view is the current controller and if it is and if the user has rotated back to portrait I need to pop the custom view and show the table view.
The table view has to rotate back to portrait, which really is okay as long as the user doesn't see it. When I create custom animations it works pretty good except for some odd invisible black box that seems to rotate with the device right before I fade out the customview to the tableview.
Further inorder to ensure that my tableview will rotate to portrait I have to allow the customview to support all orientations because the system looks to the current view (in my code) as to whether or not that app is allowed to rotate to a certain orientation. Because of this I many proposed solutions will show the customview rotating to portrait as the table view comes back to focus.
My other problem is very similar. If you are viewing the tableview and rotate the modalview of the customview is presented. When you make a selection on this view it pushes the UIScrollview onto the stack, but because the Tableview only supports portrait the UIScrollview comes in in portrait while the device is in landscape mode.
How can I overcome these awful blocks?
This is my current attempt:
When it comes to working with UITabBarController the system really only cares what the tabbarcontroller has to say about rotation.
Currently whenever a view loads it reports it supported orientations.
TabBarController.m
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
switch (self.supportedOrientation) {
case SupportPortraitOrientation:
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:YES];
return (interfaceOrientation == UIInterfaceOrientationPortrait);
break;
case SupportPortraitUpsideDownOrientation:
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:YES];
return (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
break;
case SupportPortraitAllOrientation:
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:YES];
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
break;
case SupportLandscapeLeftOrientation:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
break;
case SupportLandscapeRightOrienation:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
break;
case SupportLandscapeAllOrientation:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
break;
case SupportAllOrientation:
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
}else {
//[[UIApplication sharedApplication] setStatusBarHidden:NO animated:YES];
}
return YES;
break;
default:
return (interfaceOrientation == UIInterfaceOrientationPortrait);
break;
}
}
This block of code is part of my UINavigationController and is in a method that responds to the UIDeviceOrientationDidChangeNotification Notification. It is responsible for poping the customview and showing the tableview. There are two different versions in place that originally were for two different versions of the SDK but both are pretty close to solutions.
The reason the first is not supported on 3.0 is for some reason you can't have a view showing and then showen as a modal view. Not sure if that is a bug or a feature.
The second solution works pretty good except that I see an outer box rotating around the iphone.
if ([[self topViewController] isKindOfClass:FlowViewController.class]) {
NSString *iphoneVersion = [[UIDevice currentDevice] systemVersion];
double version = [iphoneVersion doubleValue];
if(version > 3.0){ //1st solution
//if the delivered app is not built with the 3.1 SDK I don't think this will happen anyway
//we need to test this
[self presentModalViewController:self.flowViewController animated:NO];
//[self toInterfaceOrientation:UIDeviceOrientationPortrait animated:NO];
[self popViewControllerAnimated:NO];
[self setNavigationBarHidden:NO animated:NO];
[self dismissModalViewControllerAnimated:YES];
}else{ //2nd solution
DLog(@"3.0!!");
//[self toInterfaceOrientation:UIDeviceOrientationPortrait animated:NO];
CATransition *transition = [CATransition animation];
transition.duration = 0.50;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFade;
CATransition *tabBarControllerLayer = [CATransition animation];
tabBarControllerLayer.duration = 0.50;
tabBarControllerLayer.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
tabBarControllerLayer.type = kCATransitionPush;
tabBarControllerLayer.subtype = kCATransitionFade;
[self.tabBarController.view.layer addAnimation:transition forKey:kCATransition];
[self.view.layer addAnimation:transition forKey:kCATransition];
[self popViewControllerAnimated:NO];
[self setNavigationBarHidden:NO animated:NO];
}
[self performSelector:@selector(resetFlow) withObject:nil afterDelay:0.75];
}
I'm near convinced there is no solution except for manual rotation which messes up the keyboard rotation.
Any advice would be appreciated!
Thanks.