前些日子处理了一些关于页面中的屏幕旋转的事情,需要根据某个页面的不同旋转方向去做不同的处理,现在再次总结一下,以在心里有个系统的体系,也可以当成工具文章查询。
首先来看第一个方法:
[UIDevice currentDevice].orientation
可以看到这个属性返回的是设备的物理方向,并且我们发现这个属性是只读的, UIDeviceOrientation 是硬件设备的方向,这个方向是随着硬件自身改变而改变的,只能取值,不能赋值。
typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
UIDeviceOrientationUnknown, //值是0,以下依次递增1
UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom
UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top
UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right
UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left
UIDeviceOrientationFaceUp, // Device oriented flat, face up //设备屏幕朝上
UIDeviceOrientationFaceDown // Device oriented flat, face down //设备屏幕朝下
} __TVOS_PROHIBITED;
上面是UIDeviceOrientation的枚举,我们的设备处于三维空间中,因此有6个方向。
我们可以通过添加:
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(deviceChange)
name:UIDeviceOrientationDidChangeNotification object:nil];
UIDeviceOrientationDidChangeNotification
这个通知来监听当前设备的物理方向:
-(void)deviceChange{
NSLog(@"设备旋转");
NSLog(@"当前设备方向:%ld",[UIDevice currentDevice].orientation);
}
接着来看第二个方法:
[UIApplication sharedApplication].statusBarOrientation
从上图中我们可以看到,这个值返回的是当前app的status bar的方向,即状态栏的方向,并且该属性也是只读的。
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
UIInterfaceOrientationUnknown = UIDeviceOrientationUnknown,
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
} __TVOS_PROHIBITED;
这是UIInterfaceOrientation的枚举,因为状态栏所处于一个平面,所以只有四个方向。
注意看最后两项:
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
为什么正好是相反的呢?
这样想,当设备向左旋转的时候,设备中的画面需要向右旋转,因此是相反的(不太清楚的打开模拟器旋转几下屏幕,注意看状态栏的方向改变和设备的方向改变,一对比就可以明白了)。
同的样我们可以监听:
UIApplicationDidChangeStatusBarOrientationNotification
这个事件来监听当前的设备的状态栏的方向,
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(change)
name:UIApplicationDidChangeStatusBarOrientationNotification object: nil];
-(void)change{
NSLog(@"状态栏改变了");
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
NSLog(@"%ld",(long)orientation);
}
注意的点:
1.设置状态栏方向的方法已经被弃用了。
2.我们可以使用下面这个枚举,使用起来更加便捷。
typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {
UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
} __TVOS_PROHIBITED;
如何控制:
(1)被动:
被动的意思就是,我们通过改变支持的自动旋转的方向来让app在有些方向上可以跟着旋转而有些方向上不行
* [General]->[Deployment Info]中:
* 或是在info.plist中:
虽然看起来一个是Device Orientation一个是interface orientations但是这两个地方是同步的,表示界面支持的自动旋转的方向,
而且这里对Device Orientation的改变不会影响app内获取设备的物理方向。
* 在AppDelegate中:
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
}
这里也可以设置,可以结合前面那个 UIInterfaceOrientationMask
* 在具体的UIViewController中:
//是否会跟随设备方向自动旋转,如果设置为NO,后两个方法不再调用
- (BOOL)shouldAutorotate {
return YES;
}
//返回直接支持的方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
//返回最优先显示的屏幕方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
1.这三种方式控制规则的交集就是一个viewController的最终支持的方向;
如果最终的交集为空,在iOS6以后会抛出UIApplicationInvalidInterfaceOrientationException崩溃异常。
2.第二个方法,在iPad上的默认返回值是UIInterfaceOrientationMaskAll,iPhone上的默认返回值是UIInterfaceOrientationMaskAllButUpsideDown;
3.在前面DeviceOrientation即使全部勾选了,若要iPhone支持UpsideDown,也要在viewcontroller里重写第二个方法。返回包含UpsideDown的方向;
4.第三个方法,比如同时支持Portrait和Landscape方向,但想优先显示Landscape方向,那软件启动的时候就会先显示Landscape,在手机切换旋转方向的时候仍然可以在Portrait和Landscape之间切换;
5.如果关闭了系统的横竖屏切换开关,即系统层级只允许竖屏时,再通过上述方式获取到的设备方向将是UIDeviceOrientationPortrait。UIInterfaceOrientation也将不会改变。
6***.第三种方式只有在当前viewController是window的rootViewController。或者是通过presentModalViewController而显示出来的.才会生效。作用于viewController及其childViewController。否则UIKit并不会执行上述方法。
****作用于其childViewController单独设置某个viewController并没有效果。这种情况主要可以通过下面几种方法解决:
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return self.selectedViewController.supportedInterfaceOrientations;
}
-(BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
UINavigationController 使用self.topViewController
UITabBarController 使用self.selectedViewController
然后在viewController重写这三个方法,这样就巧妙的绕开了UIKit只调用rootViewController的方法的规则. 把决定权交给了当前正在显示的viewController.
(2)主动(有风险):
请看这个
参考 :http://www.cocoachina.com/ios/20180323/22747.html