iOS屏幕旋转的解决方案

作者: Smallwolf_JS | 来源:发表于2016-01-06 20:47 被阅读12940次

    这段时间在做跟视频有关的工作,视频嘛,肯定不是小窗口播放,在手机上播放视频肯定就是最大屏幕利用率啦,这就会用到全屏播放--也就是旋转屏幕。
    下面我就来介绍下我自己的解决方案:
    先说一个别我在网上查到的资料,这里给大家更正一个问题就是要设置app的横屏还是竖屏在Xcode里面有很多设置的

    系统支持横屏顺序
    默认读取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较底层,在上面两个方法能够解决问题的情况下建议不要用,使用不当性能损耗非常大)。
    

    欢迎关注我的微博博客

    相关文章

      网友评论

      • 王乐_57bc:请问,如何实现设备方向锁定
        Smallwolf_JS:@王乐_57bc 可以参考一些播放器的实现,放置一个锁屏按钮,再点击按钮的时候把旋转的事件关闭就可以了
      • 七里小晴天:(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation 这个方法并不是默认显示的方向
      • 吴德馨:我是 TabBarVC 做 rootVC 的,希望在 TabBar的B界面一定要横屏展示,从 B 返回 A 的时候仍然竖屏展示(除 B 外其他界面都是竖屏),试了很多方法效果都不理想,怎么实现呢?
        Smallwolf_JS:@请问一个月 我知道了,那就在A界面设置为竖屏,TabbarViewController里面设置为竖屏,但是唯独在B界面设置为横屏就可以实现你说的效果了
        吴德馨:@Smallwolf_JS A 界面是Tabbar的一个item,点击 A 中的按钮会跳到 B 界面。
        Smallwolf_JS:@请问一个月 B界面是不是Tabbar的一个item啊?
      • 0bc1476dc110:今天试了在UIViewController上面重写几个方法 旋转的话是不是界面一定要模态弹出的
        Smallwolf_JS: @BigFun 可以自定义跳转方式,但是一般的模态就挺好的,旋转push效果也不会很好吧
        0bc1476dc110:@Smallwolf_JS @Smallwolf_Jpush没反应 强制横屏push也没用的样子
        Smallwolf_JS: @BigFun push不是不可以,但是会很丑,而且你的UI不是很严谨的话会出错的
      • 0bc1476dc110:非常感谢
        Smallwolf_JS: @BigFun 客气
        Smallwolf_JS:@BigFun 互相学习,客气
      • 向钱冲啊:请问 UIDevice currentDevice 这个方法好像是私有方法吧,上线会被拒么?
        Smallwolf_JS:@向钱冲啊 这个方法可以达到效果,但不建议使用,有被拒危险,我没有试

      本文标题:iOS屏幕旋转的解决方案

      本文链接:https://www.haomeiwen.com/subject/ttkzhttx.html