最近接手了一个老项目,还是oc写的。可能经过了很多手,其中的屏幕旋转方法写了很多种。有些假横屏,有些强制横屏,有些真横屏。有些地方需要横屏却横不过来。有些却横屏后恢复竖屏导致布局错乱。复习了一下oc横屏方法,准备全部重新写一下。
关于ios开发中,控制界面的展示方向(通俗来说就是横屏竖屏)。我们发现有很多相关的属性设置,目前比较常见的是5个地方。分别是
- Target → General → Deployment Info → iPhone Orientation。写displayname那边的勾选框,也就是info.plist中声明的屏幕方向。
2.AppDelegate:- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 运行时方法
3.- (BOOL)shouldAutorotate。
4.- (UIInterfaceOrientationMask)supportedInterfaceOrientations
5.- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation
这5个属性有些相互影响,有些设置了不起作用,不了解的话可能会比较迷惑。
下面我打算比较简单粗暴的说一下他们之间的关系,和最最简单的控制屏幕的方法。
第一个:
Target → General → Deployment Info → iPhone Orientation。

这里的配置,并不是硬性限制。可以理解为初始化设置,当你其他什么都没设置时,应用进来的方向,就以它为准。
第二:
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
这个方法才是真正决定屏幕最终方向的方法,可以覆盖方法1的设置。(原因:对于UIApplicationDelegate的这个方法声明,大多数情况下application就是当前的application,而window通常也只有一个。所以这个方法对横屏竖屏interfaceOrientation的控制相当于全局的。)
如果这里面你设置了
return UIInterfaceOrientationMaskPortrait;
那无论你其他怎么设置,就永远是竖屏。
所以我们讨论的是 这个方法中 你返回的是多种方向,例如:
return UIInterfaceOrientationMaskAllButUpsideDown;
那么,它现在允许你的界面根据设备的方向更换界面方向了。那如何才能让有些页面可以横屏,有些页面不可以横屏呢?
接下来,就要提到上述第三个方法ViewController.shouldAutorotate。
第三:
- (BOOL)shouldAutorotate {
return YES;
}
(这个方法不写的话,默认为是return yes)
这是一个可以在子类重写的方法,
当你return yes:就相当于打开了旋转开关,当方法二中返回UIInterfaceOrientationMaskAllButUpsideDown。 你的页面就会根据设备的方向而改变为横屏或竖屏。
当你return NO:就相当于关闭了旋转开关。页面永远保持为,刚进入这个页面时候的方向。
然后是第四个方法:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
这个方法原意是控制某个子页面的可旋转方向的范围,页面初始化的时候会调用。但是你会发现- (UIInterfaceOrientationMask)supportedInterfaceOrientations常常不起作用。
原因:这个代码需要放在决定了视图方向的controller中,比如rootviewcontroller中。或者当前导航控制器的第一个present出来的viewcontroller中。然后其旋转方向又回被方法二覆盖。所以才导致常常不起作用的错觉。(其实确实没啥用)
最后就是第五个方法
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation{
return self.topViewController.preferredInterfaceOrientationForPresentation;
}
这个方法是一个回调方法,决定了viewController出现时的视图方向,该回调方法只对present方式进入界面的viewController有效果。一般用在present vc的时候模态弹出。来确定页面方向。用的不多。
然后总结就是项目中控制页面横屏的方案。举例:一个项目,大多数页面都是竖屏,偶尔几个如视频播放页,手写签名页面等等需要横屏。
1.target → General → Deployment Info → iPhone Orientation 仅仅勾选Portrait。
2.项目中写一个父类BaseviewController,在里面写
- (BOOL)shouldAutorotate {
return NO;
}
其他页面继承BaseviewController。 需要横屏的页面重写
- (BOOL)shouldAutorotate {
return YES;
}
3.在AppDelegate中
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
应该就可以了。
最后在说一下强制横屏和假横屏。
强制横屏:设备其实我没有横着拿,但是我让界面横屏,典型例子就是 播放器全屏按钮。
NSNumber *orientationTarget = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:orientationTarget forKey:@"orientation"];
假横屏:就是其实ViewController没有横屏,只是把界面里面的Views 就是subview们给旋转了。
/// 根据当前 view 的宽高,做「内部伪横屏」的布局与旋转
- (void)layoutPseudoLandscapeAnimated:(BOOL)animated {
CGFloat screenW = self.view.bounds.size.width;
CGFloat screenH = self.view.bounds.size.height;
// 无论外部实际方向如何,内部一律按「横屏」尺寸来排版:
// viewW = 长边,viewH = 短边
CGFloat viewW = MAX(screenW, screenH);
CGFloat viewH = MIN(screenW, screenH);
// 先把 baseView 的 bounds 设置成横屏的尺寸,再居中
self.baseView.bounds = (CGRect){ CGPointZero, CGSizeMake(viewW, viewH) };
self.baseView.center = CGPointMake(screenW * 0.5, screenH * 0.5);
// 签名区域铺满 baseView;签名内部的工具栏、关闭按钮等由 XTQMSignatureView 自己 layout
self.signView.frame = self.baseView.bounds;
// 外部是竖屏(H > W)时,需要把 baseView 旋转 90°;外部横屏则不旋转
CGAffineTransform target = (screenH > screenW) ? CGAffineTransformMakeRotation(M_PI_2) : CGAffineTransformIdentity;
if (animated) {
[UIView animateWithDuration:0.25
animations:^{
self.baseView.transform = target;
}];
} else {
self.baseView.transform = target;
}
}