iOS屏幕旋转的解决方案

原文链接:http://www.jianshu.com/p/c973817d40c8

系统支持横屏顺序
默认读取plist里面设置的方向(优先级最高)等同于Xcode Geneal设置里面勾选
application window设置的级别次之
然后是UINavigationcontroller
级别最低的是viewcontroller

知道了这个顺序做横屏就变得很容易了
application支持所有

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return UIInterfaceOrientationMaskAll;//支持所有方向
}

UINavigationcontroller支持竖屏

- (BOOL)shouldAutorotate//是否支持旋转屏幕{
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations//支持哪些方向{
    return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation//默认显示的方向{
    return UIInterfaceOrientationPortrait;
}

viewcontroller支持横屏(pushmodel出来)

- (BOOL)shouldAutorotate//是否支持旋转屏幕{
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations//支持哪些方向{
    return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation//默认显示的方向{
    return UIInterfaceOrientationLandscapeLeft;
}

说明一点,只要在plist或者General设置了单一方向,在工程里面的任何代码都会失效。所以想要旋转屏幕,必须让你的工程支持所旋转的方向。(但是这里还有一种方式是把当前控制器的View或者view.layer做transform旋转,但是我认为这并不是真正的旋转屏幕,一点可以证明的就是:状态条并不随着旋转)
其实这个优先级跟你的window的rootViewcontroller有关系,如果rootViewcontroller是UITabbarViewontroller,那么tabbar就类似前面所说的UINavigationcontroller,在iOS6之后好多方法发生了改变,之前的一个屏幕旋转的方法就失效了,更改位上面的方法。
其实屏幕旋转在手机里面有设置,上拉菜单就会有关闭屏幕旋转的方式,但是大家都知道好多应用在关闭屏幕旋转的时候也可以进行屏幕旋转---通过某一个按钮的事件来触发,这就是强制旋转(前提依然是你的工程设置支持你所要旋转的方向)


 


一般的不需要旋转的程序只需要勾选第一个就可以了。
由于软件需要我勾选的是第一个和第四个,在Coding之前我要告诉大家一个细节:在iOS8之后,屏幕旋转到横向的时候,状态条就会默认隐藏,我觉得苹果是默认让你获得最大的显示区域,但是对于我这个轻微强迫症的人来说,横屏也要显示状态条,以为看着那个绿色的电池比较舒服(O(∩_∩)O),具体的操作方法就是:

在info.plist文件中将 View controller-based status bar appearance 设置为NOapplication:didFinishLaunchingWithOptions:中添加下面代码

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];

如此之后你就会发现消失的状态条有乖乖的回来了。
接下来就是Coding了:
翻阅各大网站和论坛我总结了好几种方式,但是大同小异的旋转屏幕的代码,以供参考:
支持ARC版本:

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 = UIInterfaceOrientationLandscapeRight;//这里可以改变旋转的方向
            [invocation setArgument:&val atIndex:2];
            [invocation invoke];
        }

或者

//但是注意这个方法必须在general里面设置支持锁旋转的方向,否则就是强行旋转,会导致程序崩溃,而且不会有崩溃日志,很难发现崩溃在哪里,所以使用这个方法的时候一定要注意设置支持的方向。
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];

不支持ARC版本

if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
        [[UIDevice currentDevice] performSelector:@selector(setOrientation:)
                                       withObject:(id)UIInterfaceOrientationLandscapeRight];
    }

还有一点就是如何判断当前屏幕的方向:可以根据电源的现实方向来判断,苹果提供了这一方法

NSInteger i = [[UIApplication sharedApplication] statusBarOrientation];
if (i == UIInterfaceOrientationLandscapeRight){
  //在这里可以写相应的代码
}

有些人可能想要监听屏幕的自动旋转:

1.注册UIApplicationDidChangeStatusBarOrientationNotification通知(举例:在一个viewcontroller类的viewdidload中注册该通知),示例代码如下:
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:)name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
- (void)statusBarOrientationChange:(NSNotification *)notification{
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationLandscapeRight) // home键靠右{
        //
    }
    if (orientation ==UIInterfaceOrientationLandscapeLeft) // home键靠左 {
        //
    }
    if (orientation == UIInterfaceOrientationPortrait){
        //
    }
    if (orientation == UIInterfaceOrientationPortraitUpsideDown){
        //
    }
}
注意这种方式监听的是StatusBar也就是状态栏的方向,所以这个是跟你的布局有关的,你的布局转了,才会接到这个通知,而不是设备旋转的通知。当我们关注的东西和布局相关而不是纯粹设备旋转,我们使用上面的代码作为实现方案比较适合。
2.注册UIDeviceOrientationDidChangeNotification通知(举例:我们同样在一个viewcontroller类的viewdidload中注册该通知),示例代码如下:

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientChange:)name:UIDeviceOrientationDidChangeNotification object:nil];

- (void)orientChange:(NSNotification *)noti
{

    NSDictionary* ntfDict = [noti userInfo];

    UIDeviceOrientation  orient = [UIDevice currentDevice].orientation;
    /*
     UIDeviceOrientationUnknown,
     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   */

           switch (orient)
        {
            case UIDeviceOrientationPortrait:

                break;
            case UIDeviceOrientationLandscapeLeft:


                break;
            case UIDeviceOrientationPortraitUpsideDown:


                break;
            case UIDeviceOrientationLandscapeRight:


                break;

            default:
                break;
        }
}
注意到这种方式里面的方向还包括朝上或者朝下,很容易看出这个完全是根据设备自身的物理方向得来的,当我们关注的只是物理朝向时,我们通常需要注册该通知来解决问题(另外还有一个加速计的api,可以实现类似的功能,该api较底层,在上面两个方法能够解决问题的情况下建议不要用,使用不当性能损耗非常大)。

 



文/Smallwolf_JS(简书作者)
原文链接:http://www.jianshu.com/p/c973817d40c8
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
posted @ 2016-10-10 13:53  前路弯弯  阅读(387)  评论(0)    收藏  举报