之前项目中有个关于横竖屏的需求,原本以为是很简单的事情,随便一些就能解决,但结果发现事实并不是这样。网上也搜索了很多关于横竖屏旋转的资料,但是很难发现却不能满足当时项目中的需求,因为网上给的实现很多都是针对一个小demo而言,只是两个简单的ViewController。而实际项目中一般都会涉及tabBarControll、navigationController,网上很多资料给的并不是很完全。所以就决定给这块知识好好补充一下,记得当时研究屏幕旋转主要是参考ZFPlayer。实际屏幕旋转会因为项目结构,present,push等不同因素影响。今天就分多钟情况说明一下屏幕旋转的实现,并附带上源码下载地址。https://github.com/ZhengYaWei1992/ScreenRotate
======================第一种情况======================
常规带有tabbarController的结构,首页面都不能旋转,只有在某一个present进去的子页面可以旋转,注意这里是present,不是push。这两种情况差别很大的。
首先,要想支持屏幕旋转,必选让整个项目可以支持屏幕旋转,如下图:
a.首先在AppDelegate中添加一个全局属性。
@property(nonatomic,assign)UIInterfaceOrientationMask allowRotation;
b.在AppDelegate.m中实现一个这样一个方法。
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (_allowRotation == 1) {
//支持横竖屏,注意手机只能支持三个方向,这里不能写成UIInterfaceOrientationMaskAll,否则会出现一些不可预料的问题。只有iPad才支持四个方向。
return UIInterfaceOrientationMaskAllButUpsideDown;
}
else
{
return (UIInterfaceOrientationMaskPortrait);
}
}
c.在present进去的子页面中实现的代码如下,设置支持横竖屏。
在viewDidLoad:方法中添加如下代码,设置屏幕支持旋转。
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.allowRotation = 1;
d.在离开这个界面之前我们要实现下面的代码,设置只支持竖屏。
//离开的时候要再次设置
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.allowRotation = 0;
e.如果想在屏幕旋转后做一些适配,可以在下面这个方法中实现。
//在这里布局横竖屏的UI
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.backgroundColor = [UIColor whiteColor];
NSLog(@"垂直");
}else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight || toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
self.view.backgroundColor = [UIColor redColor];
NSLog(@"横向");
}
}
======================第二种情况======================
再看第二种情况,和第一种情况基本类似,只是将present方式改成push进入子页面。虽然只是改变了一点,但是实现代码上差别很大的。
a.首先需要在tabbarController中实现以下两个方法。这两个方法的意思是将控制屏幕旋转的主动权都交给每个子页面去实现。
//是否支持旋转
-(BOOL)shouldAutorotate{
UINavigationController *navC = self.selectedViewController;
UIViewController *currentVC = navC.visibleViewController;
return [currentVC shouldAutorotate];
}
//支持的方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
UINavigationController *navC = self.selectedViewController;
UIViewController *currentVC = navC.visibleViewController;
return [currentVC supportedInterfaceOrientations];;
}
b.push进去的子页面首先要重写两个系统方法,即和tabbarViewCotroller中相同的方法。设置支持旋转,支持三个旋转方向
/是否可以旋转
- (BOOL)shouldAutorotate
{
return YES;
}
//支持的方向
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
c.但是仅仅实现上面的代码是不够的,这是如果在横屏状态下返回上一界面,会发现上一界面也是处于横屏状态。这和我们的初衷不一样,我们想的是上一界面支持竖屏状态,不会受到子页面的影响。解决办法是在子页面返回的时候实现以下代码。
//这里的目的是为了使返回时,上一界面依然是竖屏
-(void)viewWillDisappear:(BOOL)animated{
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = UIInterfaceOrientationPortrait;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
d.同样,子页面横竖屏界面的适配同样可以在以下这个方法中实现。
//在这里布局横竖屏的UI
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.backgroundColor = [UIColor whiteColor];
NSLog(@"垂直");
}else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight || toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
self.view.backgroundColor = [UIColor blackColor];
NSLog(@"横向");
}
}
e.其他不支持横竖屏切换的控制器,都要实现以下方法。
- (BOOL)shouldAutorotate
{
return NO;
}
//支持的方向
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
======================第三种情况======================
这一次我们只让present的子页面,只支持横屏,不支持竖屏。而其他控制器支持竖屏。实现起来很简单,只是在第一种情况中做一个小小的变动。将第一种情况中的b步骤实现代码改为如下代码,其他实现代码和第一种情况相同。
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (_allowRotation == 1) {
NSLog(@"appDelegate横屏");
return UIInterfaceOrientationMaskLandscapeRight;
}
else
{ NSLog(@"appDelegate竖屏");
return (UIInterfaceOrientationMaskPortrait);
}
}