首页 > 代码库 > 横竖屏任意切换 实战浅析

横竖屏任意切换 实战浅析

前话:前前后后弄了一下午,尝试各种解决方案(估摸有一二十种吧),最后误打误撞终于解决,鉴于在国内国外查找各种解决方法都未能解决,故有此文。(当然stackOverFlow 各种新奇的解决方案,我一一尝试实战,却未能解决,可能是英文还不够好,理解国外解决方案的不够透彻所致,不过稍感欣慰,还是解决了;不管黑猫白猫,能抓耗子就是好猫吧;还真是应了这句话)

 

需求:整个APP中界面以竖屏为主,且不能自动横竖屏切换,个别播放视频页面可以根据手机的方向横竖屏切换或固定横屏;

 

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

注:其实这个优先级跟你的window的rootViewcontroller有关系,如果rootViewcontroller是UITabbarViewontroller,那么tabbar就类似前面所说的UINavigationcontroller

 

翻阅各大网站和论坛我总结了好几种方式,但是大同小异的旋转屏幕的代码,以供参考:
支持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];        }

或者

//强行旋转,(会导致程序崩溃,而且不会有崩溃日志,很难发现崩溃在哪里,所以使用这个方法的时候一定要注意设置支持的方向) -->  我反正没遇到 我用着好好的

如何手动旋转设备?

Objective-C:

NSNumber *value = http://www.mamicode.com/[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];"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较底层,在上面两个方法能够解决问题的情况下建议不要用,使用不当性能损耗非常大)。

 



 

1.在项目中用代码控制视图是否能够自动旋转,支持哪些方向主要是用了下面的三个方法:

 

[objc] view plain copy
 
 技术分享技术分享
  1. // New Autorotation support.  
  2. //是否自动旋转,返回YES可以自动旋转  
  3. - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;  
  4. //返回支持的方向  
  5. - (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;  
  6. // Returns interface orientation masks.  
  7. //这个是返回优先方向  
  8. - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;  

 

一般情况下实现前两个方法即可!!这些都是UIViewController的实例方法,直接在需要设置的控制器重写就行...

 

 

2.简单介绍我试过的集中方法

1.  这个方法别人说能用,我用了没效果,当时也没看别人的Demo  ; 可能有效果吧  ,Demo 见下方


[objc]
 view plain copy
 
 技术分享技术分享
  1. //强制旋转屏幕  
  2. - (void)orientationToPortrait:(UIInterfaceOrientation)orientation {  
  3.     SEL selector = NSSelectorFromString(@"setOrientation:");  
  4.     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];  
  5.     [invocation setSelector:selector];  
  6.     [invocation setTarget:[UIDevice currentDevice]];  
  7.     int val = orientation;  
  8.     [invocation setArgument:&val atIndex:2];//前两个参数已被target和selector占用  
  9.     [invocation invoke];  
  10.       
  11. }  


调用的时候只需把你想要的方向传过去即可!!

使用的时候有个点需要注意,从A进入B的时候,把B强制转换成横屏,返回的时候,需要在A出现的时候再转换为原来的方向,不然会有问题;个人建议可以在B的viewWillAppear调用这个方法,转换屏幕(例如转换为横屏),然后在A的viewWillAppear中转换回来;

 

最后附上以上内容的Demo:Demo地址

 

 

2.这里有一个用JS 和原生item 控制横竖屏切换的Demo。地址

 

 

3.我的方案:

其他界面不支持横屏:

播放界面横屏:

Step1:

在APPDelegate.h文件中增加属性:是否支持横屏

/***  是否允许横屏的标记 */@property (nonatomic,assign)BOOL allowRotation;

在APPDelegate.m文件中增加方法,控制全部不支持横屏

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {    if (self.allowRotation) {        return UIInterfaceOrientationMaskAll;    }    return UIInterfaceOrientationMaskPortrait;}

 Step2:

竖屏界面A 跳到 横屏界面B 

首先竖屏界面A 配置,直接贴代码了;

- (void)viewDidAppear:(BOOL)animated {

    [super viewDidAppear:animated];

    NSNumber *value = http://www.mamicode.com/[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];

    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];

}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

    return UIInterfaceOrientationMaskPortrait;

}

 

横屏界面B

- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

    return UIInterfaceOrientationMaskLandscape;

}

 

好,关键的两步来了;

1.竖屏界面A 跳到 横屏界面B  一定用presentViewController 跳转 (不知道我说的什么法的,下面的可以不看了)

注:.竖屏界面A---》CFMatchPlayBackViewController   横屏界面B:IJKVideoViewController

 IJKVideoViewController *ijk = [[IJKVideoViewController alloc] initWithURL:[NSURL URLWithString:self.replyPath]];

            CFMatchPlayBackViewController *VC =   ((CFMatchPlayBackViewController *)nextResponder);

        __weak __typeof(VC)weakSelf = VC;

            ijk.deviceTap = ^ {

                NSNumber *value = http://www.mamicode.com/[NSNumber numberWithInt:UIInterfaceOrientationPortrait];

                [[UIDevice currentDevice] setValue:value forKey:@"orientation"];

            };

            [((UIViewController *)nextResponder) presentViewController:ijk  animated:YES completion:nil];

2.横屏界面B 跳转到 竖屏界面A 

    [self.presentingViewController dismissViewControllerAnimated:NO completion:^{

        //

        self.deviceTap();

    }];

 

3.重点:   本来这样跳,苹果本身自己是有一个Bug的,就是dismiss掉,回来依然是横屏,而且还是不自适应的横屏;不过解决办法就是 ---->  见下图

技术分享

 

 4.UIView 横竖屏;最下层加一个View,利用UIView 旋转方法;不失为好方法,亲测也是可用的好办法;看需求吧

后记: 写文章真的是费神费力;但鉴于找遍网上并没有很好的解决方案,故写此文,以帮助像我一样智商一般的孩子;最近赶项目很忙,等空了github 上传Demo; 留言要Demo的,传的会更快哟 !(这是有史以来我写的最清楚的文章,相信聪明的你已经Get到了)

横竖屏任意切换 实战浅析