最近在做直播,用的是腾讯云,但是主播界面需要横屏显示,而且只能横屏,整个项目也只有这个界面横屏。
发现腾讯云在这一块提供了对流的控制,但是并没有提供对界面的控制,需要自己去实现界面的控制,主要是界面各种交互,各种效果,各种逻辑,所以必须自己控制选择,期间也遇到了不少坑。
所以就整理了一下,当然这里同样适合iPad适配,相信以后在屏幕旋转和旋转相关适配这一块应该是没有问题了!
相关枚举:首先需要知道苹果提供的关于屏幕的一些枚举值
UIDeviceOrientation:
1 | typedef NS_ENUM(NSInteger, UIDeviceOrientation) { |
UIInterfaceOrientation:
1 | typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { |
从宏定义可知,device方向比interface多了两个定义:
UIDeviceOrientationFaceUp和UIDeviceOrientationFaceDown,分别表示手机水平放置,屏幕向上和屏幕向下。
两种orientation:然后就是两种相关的orientation
device orientation
设备的物理方向,由类型UIDeviceOrientation表示,当前设备方向获取方式:
1 | // return current device orientation. this will return UIDeviceOrientationUnknown unless device orientation notifications are being generated. |
注意点1:推荐方式
1 | if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) { |
注意点2:横竖屏关闭
1 | 如果关闭了系统的横竖屏切换开关,即系统层级只允许竖屏时,再通过上述方式获取到的设备方向将永远是UIDeviceOrientationUnknown。 |
interface orientation
界面显示的方向,由类型UIInterfaceOrientation表示。当前界面显示方向有以下两种方式获取:
设备的物理方向,由类型UIDeviceOrientation表示,当前设备方向获取方式:
1 | NSLog(@"%d",[UIApplication sharedApplication].statusBarOrientation); |
即可以通过系统statusBar的方向或者viewController的方向来获取当前界面方向。
区别
通过UIDevice获取到的设备方向在手机旋转时是实时的。
通过UIApplication的statusBar或者viewController获取到的界面方向在下述方法:调用以后才会被更改成最新的值。
1 | NSLog(@"%d",[UIApplication sharedApplication].statusBarOrientation); |
相关方法
1 | // Applications should use supportedInterfaceOrientations and/or shouldAutorotate.. |
如何旋转
全局控制
Info.plist文件中,有一个Supported interface orientations,可以配置整个应用的屏幕方向,此处为全局控制。
UIWindow
iOS6的UIApplicationDelegate提供了下述方法,能够指定 UIWindow 中的界面的屏幕方向:
1 | - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window NS_AVAILABLE_IOS(6_0); |
该方法默认值为Info.plist中配置的Supported interface orientations项的值。
iOS中通常只有一个window,所以此处的控制也可以视为全局控制。
controller
只有以下两种情况:
当前controller是window的rootViewController
当前controller是modal模式的时候,orientations相关方法才会起作用(才会被调用),当前controller及其所有的childViewController都在此作用范围内。
最终支持的屏幕方向
前面所述的3种控制规则的交集就是一个controller的最终支持的方向;
如果最终的交集为空,在iOS6以后会抛出UIApplicationInvalidInterfaceOrientationException崩溃异常。
总结来说改变Orientation有三种途径
当手机的重力感应打开的时候, 如果用户旋转手机, 系统会抛发UIDeviceOrientationDidChangeNotification 事件.
您可以分别设置Application和UIViewcontroller支持的旋转方向.Application的设置会影响整个App, UIViewcontroller的设置仅仅会影响一个viewController(IOS5和IOS6有所不同,下面会详细解释).
当UIKit收到UIDeviceOrientationDidChangeNotification事件的时候, 会根据Application和UIViewcontroller的设置, 如果双方都支持此方向, 则会自动屏幕旋转到这个方向. 更code的表达就是, 会对两个设置求与,得到可以支持的方向. 如果求与之后,没有任何可支持的方向, 则会抛发UIApplicationInvalidInterfaceOrientationException异常.
当然,你还可以对View进行旋转,但是这样会有一些需求上的问题,比如状态栏,键盘等就没有办法,只能自己通过其他方式控制!
1 | UIView.transform |
当然我们可以对当前viewController进行旋转, 对任何view旋转都可以.但是, 你会发现navigationBar还横在那里. 所以, 我们最好对一个占满全屏的view进行旋转. 在这里我们旋转的对象是self.navigationController.view, 当然self.window也可以, help yourself~
我们需要显式的设置bounds. UIKit并不知道你偷偷摸摸干了这些事情, 所以没法帮你自动设置.
具体实现
借助通知来控制界面的横竖屏切换。
还是整个App中大部分界面都是竖屏,某个界面可以横竖屏切换的情况。
首选这只plist只支持竖屏:Portrait(Home朝下)
然后在特殊的视图控制器里的ViewDidLoad中注册通知:
1 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; |
最重要的一点:
需要重写如下方法,并且返回NO。这样,在设备出于横屏时,界面就会变成横屏,设备处于竖屏时,界面就会变成竖屏。
1 | - (BOOL)shouldAutorotate |
但是这样会遇到两个坑
上面方式二,因为【General】–>【Device Orientation】因为只设置了竖屏,所以当横屏时,如果有键盘弹出,键盘是竖屏时的样式。
解决办法:在【General】–>【Device Orientation】中加上横屏时的方向。
如果VieController 是放在UINavigationController或者UITabBarController中,需要重写它们的方向控制方法。
1 | // UINavigationController: |
如果想要点击某个按钮之后,强制将竖屏显示的界面变成横屏呢?
有人可能会想到这样写:
1 | // 横屏 |
但是按照上面的写法,会导致返回到之前的界面时,视图方向错误,即使返回前执行如下代码:
1 | [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]; |
结果发现也没有作用,下面是在开源工程中无意看到的写法:
1 | // 横屏 |
通过属性控制
项目需求(场景): 整个项目不需要旋转(当然了,所有方向的屏幕适配都做好的情况下是没问题的,但是没有必要这么劳民伤财。)的前提下,播放界面控制器需要支持屏幕的其他方向的旋转。
先设置:targets——>general——>device Orientation——>支持的旋转方向
在 AppDelegate.m 里面
1 | -(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { |
在你想要支持 旋转的控制器 需要导入#import “AppDelegate.h”
1 | - (void)viewWillAppear:(BOOL)animated { |
当你写完这些的时候发现好像可以了,还有问题。
但你横屏播放的状态下 直接返回上个控制器(pop)的时候.
发现那个控制器也是横屏的(当你竖屏时,它会转过来,但是再旋转就不行了。问题就是pop回来不能使横屏啊,应该直接竖屏才是啊)
比如pop回的那个控制器叫 TextViewController
在TextViewController.m里
1 | //屏幕方向操作 |
此方法是UIKit框架中UIViewController.h的公布方法,iOS 6.0后加入