#前言:
项目需求:整个app都是只支持竖屏的,但当手机转为横屏模式时,需要加入另外一个横屏的视图,并且在手机转为竖屏时,应该收起当前横屏的视图并显示之前竖屏的那个界面。(类似播放视频的,当横屏时自动转为全屏的横屏播放,当转为竖屏时就会回到竖屏状态)
参考链接:
RAYWENDERLICH
官方文档
Tomson Xu
iOS 关于屏幕旋转shouldAutorotate
里脊串的开发随笔
iOS界面布局
- iOS6开始rotation变了。
UIViewController的shouldAutorotateToInterfaceOrientation方法被deprecated。使用supportedInterfaceOrientations and shouldAutorotate 2个方法来代替shouldAutorotateToInterfaceOrientation。
在iOS4和5中,如果没有重写shouldAutorotateToInterfaceOrientation,默认是只支持portrait,不能旋转。
在iOS6中,如果没有重写supportedInterfaceOrientations and shouldAutorotate,默认是可以旋转除了upside down的方向。而iPad是支持所有方向。 例子1:在iOS4、5iPhone设备中,如果想要
支持除upside down外的其它方向的旋转
则在view controller里写下如下代码:- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation != UIDeviceOrientationPortraitUpsideDown); }
例子2: 在iOS6,iPhone设备,若要
不能旋转,只能portait
,则在view controller里写下如下代码:- (BOOL)shouldAutorotate { return NO; }
例子3:在iOS6,iPad设备,若要
可以旋转,只支持landscape
,则在view controller里写下:-(NSUInteger)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskLandscape; } - (BOOL)shouldAutorotate { return YES; }
在iOS4,5中,都是由具体的view controller来决定对应的view的orientation。而在iOS 6,则是由top-most controller来决定view的orientation设置。
例如:你的app的rootViewController是navigation controller”nav”,在“nav”中的stack依次为:main view ->sub view ->sub sub view
而main view 有一个button会present modal view modal view
那么在iOS4、5,在iPad里,如果你要实现上述view都仅支持横屏orientation,你需要在上面的main view,sub view,sub sub view,model view
都添加下面的代码:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight);
}
而对于iOS6,由于是由top-most controller来设置orientation,因此你在main view,sub view,sub sub view,model view
里添加下面的代码时没有效果的,而应该添加在nav controller里。而modal view则不在nav controller中,因此在modal view中也需要添加下面的代码。
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL)shouldAutorotate
{
return YES;
}
Important
- 你需要自定义一个UINavigationController的子类,然后在里面添加上述代码。
- 和navigation controller类似,tab controller里的各个view的orientation设置应该放在tab controller里
问题
因为旋转屏幕支持的方向是由top-most controller决定的,导致这样一个问题:在 top-most controller里的views无法拥有不相同的orientation设置。例如在nav controller中,你希望sub sub view是能横能竖的,当希望其他的view只能竖屏,那么在iOS4、5中通过在sub sub view的shouldAutorotateToInterfaceOrientation
设置打竖屏和横屏都行,其他的设置只能打竖屏。但在iOS6中则无法实现这种效果,因为只有在top-most controller里设置才有效。
于是你会在nav controller里控制哪个view需要竖屏哪个view需要横屏。
-(NSUInteger)supportedInterfaceOrientations{
if([[self topViewController] isKindOfClass:[SubSubView class]])
return UIInterfaceOrientationMaskAllButUpsideDown;
else
return UIInterfaceOrientationMaskPortrait;
}
但这样子会出现一个问题:当你在sub sub view打横屏,然后back to sub view,这时的sub view也变成横屏了。
解决方案:
在tabbarcontroller中写如下代码:
/**
* 重写旋转控制的相关代码,因为在iOS6以后,设置orientation是由top-most controller来的,所以你需要在navigationController中添加下面的代码,但modal view是不属于nav controller中的,所以需要单独对modalview添加下面的代码
*/
- (BOOL)shouldAutorotate{
NSInteger index = self.selectedIndex;
//
UINavigationController *selectedNavController = (UINavigationController *)[self.viewControllers objectAtIndex:index];
//
UIViewController *topViewController = [selectedNavController.viewControllers objectAtIndex:0];
NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([selectedNavController.visibleViewController class]));
return selectedNavController.visibleViewController.shouldAutorotate;
return topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations{
NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.selectedViewController class]));
return self.selectedViewController.supportedInterfaceOrientations;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.selectedViewController class]));
return self.selectedViewController.preferredInterfaceOrientationForPresentation;
}
在navigationController中:
#pragma mark - 重写navigationController旋转代码 - (BOOL)shouldAutorotate{ NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.visibleViewController class])); return self.visibleViewController.shouldAutorotate; return self.topViewController.shouldAutorotate; } - (NSUInteger)supportedInterfaceOrientations{ NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.visibleViewController class])); return self.visibleViewController.supportedInterfaceOrientations; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{ NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.visibleViewController class])); return self.visibleViewController.preferredInterfaceOrientationForPresentation; }
在sub viewcontroller中:
-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self switchToPortrait]; } #pragma mark - 旋转 //支持的方向 -(NSUInteger)supportedInterfaceOrientations { NSLog(@"%s",__PRETTY_FUNCTION__); return UIInterfaceOrientationMaskPortrait; } //是否支持屏幕旋转 -(BOOL)shouldAutorotate { NSLog(@"%s",__PRETTY_FUNCTION__); return YES; } -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{ NSLog(@"%s",__PRETTY_FUNCTION__); return UIInterfaceOrientationPortrait; } /** * 强制转为横屏 */ - (void)switchToPortrait{ [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];//这句话是防止手动先把设备置为横屏,导致下面的语句失效. [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];
}
在sub sub viewcontroller中:
#pragma mark - 旋转 -(BOOL)shouldAutorotate{ return YES; } -(NSUInteger)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskLandscape; }
(以上是通过在sub view中push了sub sub view)
如果只是使用navigationcontroller
#pragma mark - 重写navigationController旋转代码
- (BOOL)shouldAutorotate{
NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.visibleViewController class]));
return self.visibleViewController.shouldAutorotate;
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations{
NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.visibleViewController class]));
return self.visibleViewController.supportedInterfaceOrientations;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
NSLog(@"\n%s~~~visibleVCclass:%@",__PRETTY_FUNCTION__,NSStringFromClass([self.visibleViewController class]));
return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}
在sub viewcontroller中:
#pragma mark - 旋转
//支持的方向
-(NSUInteger)supportedInterfaceOrientations
{
NSLog(@"%s",__PRETTY_FUNCTION__);
return UIInterfaceOrientationMaskPortrait;
}
//是否支持屏幕旋转
-(BOOL)shouldAutorotate
{
NSLog(@"%s",__PRETTY_FUNCTION__);
return YES;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
NSLog(@"%s",__PRETTY_FUNCTION__);
return UIInterfaceOrientationPortrait;
}
在sub sub view中
#pragma mark - 旋转
-(BOOL)shouldAutorotate{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
关键的还是强制旋转屏幕的那条语句。
- (void)switchToPortrait{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];//这句话是防止手动先把设备置为横屏,导致下面的语句失效.
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];
在iOS6中,当view controller present时,不会调用 willRotateToInterfaceOrientation:duration:
,willAnimateRotationToInterfaceOrientation:duration:
,didRotateFromInterfaceOrientation:
只有在发生rotate时才会调用。