iOS强制横屏总结

作者: sfandy | 来源:发表于2016-07-28 14:29 被阅读21249次
总体方向两点:
  • model下,present方式推出界面。
  • push横屏,带tabbar、navigation,且一个item下所有控制器对应的只有一个根navigation。

接下来说说push方式强制旋转横屏时遇到的坑吧.....

遇到的问题描述:
  • 横着,竖屏切换到横屏,是否“锁定竖屏”,都会偶尔造成无法旋转至横屏,iOS8表现较明显。
  • 横着或竖着,切换到横屏,挂起,再进入横屏,退出,再进入横屏,反复切换,偶尔会导致无法横屏,返回上竖屏时,界面返回了,但横屏无法返回。
  • 横竖屏来回切换,跳转,iOS8下,横屏控制器,竖屏控制器中init方法,横屏中viewWillDisapper、viewWillApper,调用顺序会乱,与iOS7、9执行的顺序不一样,个人感觉应该是push强制横屏或都是同一个navigation导致的原因吧。
小总结下:
  • 由于该项目横屏中有来回跳转,到处跳转的,一个item下对应的根控制下又只能是同一个navigation,分享模块又是基于tabbar上的navigation推出的,分享模块无回调,导致我瞻前顾后的,一直盯着push方式到底是否可以强制旋转屏幕........百般绞尽脑汁的研究

  • 思来想去的,就参考了爱奇艺横屏播放视频的方式,横屏中的跳转都先回到竖屏播放控制器中跳转,相当于横屏中跳转多了一层过渡控制器;竖屏返回,应该是返回根控制器,所以,横屏应该是一个新的navigation,而分享都是在横屏中处理的。而我这项目中,分享的列表是在tabbar上的navigation加在windows上的,分享跳转都是基于tabbar的navigation,故无法再新建navigation,否则会引发一系列问题,比如无法跳转至首页,基本上各种在横屏里面的老代码跳转方式都不行了。

故此,我又回到全部push方式继续坑........

因为我也不想啊,如果用present方式涉及改动的代码模块太多了.....

其实有点不明白的是,产品为何如此设计:横屏和竖屏,全模块之间的跳转,试问这样真的好吗.........

接下来分析下push方式,仅限于参考和积累问题吧:

解决方案:

先说下思路吧:

1.实时的更新当前应用所支持的方向,手动调用方法-    (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;
2.把当前控制器的方向给到当前navigation,一定要保证统一,不能乱套,否则会导致界面来回跳转错乱的问题;
3.及时刷新当前控制器,手动调用方法[UIViewController attemptRotationToDeviceOrientation]。

一、 present方式:
就不多说了,调用系统的三个方法,基本上没什么问题。

二、push方式:

  • 基类tabbar代码:
    #pragma mark - - orientation
    // 是否支持转屏
    - (BOOL)shouldAutorotate
    {
    return [self.selectedViewController shouldAutorotate];
    }
    // 返回nav栈中的最后一个对象支持的旋转方向
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations
    {
    return [self.selectedViewController supportedInterfaceOrientations];
    }
    // 返回nav栈中最后一个对象,坚持旋转的方向
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
    return [self.selectedViewController preferredInterfaceOrientationForPresentation];
    }

  • 基类navigation代码:
    //旋转方向 默认竖屏
    @property (nonatomic , assign) UIInterfaceOrientation interfaceOrientation;
    @property (nonatomic , assign) UIInterfaceOrientationMask interfaceOrientationMask;

    #pragma mark - - orientation
    //设置是否允许自动旋转
    - (BOOL)shouldAutorotate {
        return YES;
    }
    
    //设置支持的屏幕旋转方向
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
      return self.interfaceOrientationMask;
    }
    
    //设置presentation方式展示的屏幕方向
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
      return self.interfaceOrientation;
    }
    
  • 基类BaseViewController代码:
    - (void)viewDidLoad
    {
    [super viewDidLoad];
    [UIViewController attemptRotationToDeviceOrientation];
    }

  • AppDelegate代码
    @property (assign , nonatomic) BOOL isForceLandscape;
    @property (assign , nonatomic) BOOL isForcePortrait;

    -(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
      if (self.isForceLandscape) {
          return UIInterfaceOrientationMaskLandscape;
      }else if (self.isForcePortrait){
          return UIInterfaceOrientationMaskPortrait;
      }
      return UIInterfaceOrientationMaskPortrait;
    }
    
  • 横屏viewController代码:
    重点说明:
    1.此处需要手动调用
    - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;
    且设置当前 应用只支持横屏;
    因为,该方法在viewWillAppear之后执行的。
    2.更新了支持的方向后,记得刷新下控制器,调用:
    [UIViewController attemptRotationToDeviceOrientation];
    否则,[UIScreen mainScreen].bounds的size不是你期望的;self.view.frame/bounds都不是期望的。
    3.其实网上说的一些普通的方式实现横屏,问题多,更多的是因为self.view.frame/bounds/[UIScreen mainScreen].bounds没有及时更新的。

    - (void)viewWillAppear:(BOOL)animated
      {
        [super viewWillAppear:animated];
        //强制旋转竖屏
        [self forceOrientationLandscape];
        CKNavigationController *navi = (CKNavigationController *)self.navigationController;
        [self.navigationController setNavigationBarHidden:YES animated:animated];
        navi.interfaceOrientation =   UIInterfaceOrientationLandscapeRight;
        navi.interfaceOrientationMask = UIInterfaceOrientationMaskLandscapeRight;
    
        //强制翻转屏幕,Home键在右边。
        [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeRight) forKey:@"orientation"];
        //刷新
        [UIViewController attemptRotationToDeviceOrientation];
    }
    

  重点说明:
  1.离开横屏时、横屏中跳转,记得强制旋转至竖屏;
  2.如果没有及时旋转至横屏,会导致[UIScreen mainScreen].bounds没有及时更新,从而影响其它模块的布局问题;

 - (void)viewWillDisappear:(BOOL)animated 
  {
    [super viewWillDisappear:animated];
     //强制旋转竖屏
    [self forceOrientationPortrait];
    CKNavigationController *navi = (CKNavigationController *)self.navigationController;
    navi.interfaceOrientation = UIInterfaceOrientationPortrait;
    navi.interfaceOrientationMask = UIInterfaceOrientationMaskPortrait;

     //设置屏幕的转向为竖屏
    [[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"];
    //刷新
    [UIViewController attemptRotationToDeviceOrientation];
   }

  #pragma  mark 横屏设置
  //强制横屏
- (void)forceOrientationLandscape
  {
    CKAppDelegate *appdelegate=(CKAppDelegate *)[UIApplication sharedApplication].delegate;
    appdelegate.isForceLandscape=YES;
    appdelegate.isForcePortrait=NO;
    [appdelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
  }

  //强制竖屏
 - (void)forceOrientationPortrait
  {
    CKAppDelegate *appdelegate=(CKAppDelegate *)[UIApplication sharedApplication].delegate;
    appdelegate.isForcePortrait=YES;
    appdelegate.isForceLandscape=NO;
    [appdelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
  }

- (BOOL)prefersStatusBarHidden{
    return YES;
}
感受
  • 网上找了很多种方法,关于
    这个方法有人说上架可能会被拒,虽然是间接调用私有方法。
    但这个方法经过多轮测试,其实不是有用的,不靠谱,只要按照我上面说的步骤测试,绝对会有bug的,故此不建议大家使用该方法。

     - (void)interfaceOrientation:(UIInterfaceOrientation)orientation{
      if([[UIDevicecurrentDevice] respondsToSelector:@selector(setOrientation:)]) {        
          SEL selector  =NSSelectorFromString(@"setOrientation:");
          NSInvocation*invocation = [NSInvocationinvocationWithMethodSignature:[UIDeviceinstanceMethodSignatureForSelector:selector]];     
          [invocation setSelector:selector];        
          [invocation setTarget:[UIDevicecurrentDevice]];
          intval = orientation;
          // 从2开始是因为0 1 两个参数已经被selector和target占用
          [invocation setArgument:&val atIndex:2];                                                     
          [invocation invoke];   
      }}
    

以上所述,支持iOS7、8、9系统,经iphone \iPod测试过,但貌似iOS8从横屏挑战至其它竖屏的界面,偶尔会有问题,概率很小,不影响。
原因:可能是iOS8 SDK与其它不同吧。

更新iOS8的问题:

   iOS8-8.4,横屏跳转至其它界面,最好延迟跳转,不然其它界面的viewWillApper会比横屏的viewWillDisApper先执行,导致无法旋转回来。
   CGFloat timef = 0.8;
    //主要是转屏之后view的再次旋转
    if (kSystemVersion>8||kSystemVersion<8.4) {
        self.view.hidden = YES;
        [self viewWillDisappear:NO];
        timef = 0.1;
    }
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, timef*NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^{
        dispatch_async(dispatch_get_main_queue(), ^(){
           //跳转界面
        });
    });

参考资料:
http://www.cocoachina.com/bbs/read.php?tid=244119

相关文章

  • iOS强制横屏

    iOS强制横屏

  • iOS强制横屏总结

    总体方向两点: model下,present方式推出界面。 push横屏,带tabbar、navigation,且...

  • iOS 强制横屏(Push和模态)

    # iOS 强制横屏(Push和模态) iOS开发过程中,有时候需要页面强制横屏。 下面这种方法是不管手机有没有开...

  • iOS 横竖屏处理

    开发中有竖屏和横屏的界面时,我们需要监听屏幕旋转,强制横屏,锁定方向后的屏幕强制旋转等处理.以下做个总结: 一.横...

  • iOS强制横屏

    朋友给的场景,一个vc present一个nav包着一个vc,这个被present出来的vc要求横屏,dismi...

  • iOS强制横屏

    前言 最近在项目中有一个需求,就是进入某一个页面时要强制横屏,其他界面不做限制,查了资料发现有些方法对我的需求只有...

  • iOS 强制横屏

    NSNumber *orienTarget=[NSNumber numberWithInt: UIInterfac...

  • iOS强制横屏

    项目有一个需求:项目中某一个视图控制器需要强制横屏(或竖屏),并且不能转屏;其他的控制器横竖屏都可以。查了很多资料...

  • iOS强制横屏

    1.http://www.cnblogs.com/block123/p/5917770.html 2.http:/...

  • ios强制横屏

    在强制横屏的页面重新加载init方法:(ios8后会隐藏状态栏) ios8 以后横屏状态栏不显示 解决方法:

网友评论

  • 不辣先生:横屏的时候通知从侧面出来,有什么解决方案,大神
  • 不辣先生:横屏下如何强制隐藏tabbar?
  • Funnyer:我只是调用了这两句代码,就可以达到效果了://设置屏幕的转向为竖屏
    [[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"];
    //刷新
    [UIViewController attemptRotationToDeviceOrientation];
    Funnyer:@快乐的一直小青蛙 每次强制变换要记得刷新:[UIViewController attemptRotationToDeviceOrientation];
    快乐的一直小青蛙:很棒棒诶,找了很多方法,没想到用你的两句代码就可以搞定
    Funnyer:但是反复进入需要横屏的webView,[UIDevice currentDevice].orientation = UIDeviceOrientationUnknown,怎么回事?
  • zcz:感谢楼主,完美的解决我的问题:+1:
    sfandy:@zcz :+1:
  • Rhythm_Ting:在iOS11 下,从横屏回到竖屏,tabbar 上的图标全都挤到一起去了,可能是什么原因引起的呢 ? 其他版本的系统没影响
  • timeforasong:好,找了很多办法,这是唯一能用的!
  • 假能干:老哥~按照上面的代码,我试着写了一下~ 已经实现push指定界面横屏~ 回到上界面不影响上界面布局, 目前出现唯一问题为:横屏界面布局失败,布局frame位置为竖屏适配。
    在viewWillAppear方法中手动调用了老哥你的forceOrientationLandscape(强制横屏)方法
    而后在viewWillAppear方法中刷新:
    [UIViewController attemptRotationToDeviceOrientation];
    但是未能实现横屏的布局~
    想到了,回到竖屏成功可能是因为,根本就没有将布局转为横屏,所以未能影响竖屏的布局。
    老哥~这种问题方便帮我分析一下么~
  • 叫我困兽:按照你的方法,控制器可以横屏。但是我想在横屏的控制器中增加子控制器,自控制器使用自定义初始化方法,来设置这个子控制view的fram出现了问题。fram的size完全对不上.....不是横竖颠倒,而是都是错误的,请问你遇到这这个问题么?是哪里错了?
    叫我困兽:知道问题了,是因为viewDidLayoutSubviews时候重新绘制frame了。要是修改子控制的view需要在这里绘制。就好了
  • 5ec1da87f063:看到最后,其实这个方法并不靠谱吗?....使用私有api,不是每次都管用.是这样吗?
    sfandy:@5ec1da87f063 私有API不能使用。
    sfandy:@5ec1da87f063 自己看清楚,不会用到私有api
  • 尕宝11:@秘制鸭腿 我项目需求只有播放也可以全屏,我的全屏是手动修改约束实现的,在横屏滑动修改音量的时候,音量的提示框还是竖屏的样子,该怎么解决啊?很急
    秘制鸭腿:我是强制横屏的,你可以尝试一下、只是偶尔会出现bug。
  • 三分慢先森:在A控制器中播放视频手机横屏,然后pop至B控制器,手机仍然横着放,但是要让B控制器屏幕转换为竖屏状态,此过程中supportedInterfaceOrientations方法成功返回了只支持竖屏的状态,屏幕不改变,然后调用attemptRotationToDeviceOrientation方法,屏幕仍不改变,请问怎么解决呢
  • ac6ff43241d6:转屏的时候,报内存警告,崩了,怎么解决???有谁遇到没???
  • ac6ff43241d6:用的是 UIImagePickerController 选择相册图片 pressent 的时候崩的,说方向不对,这个时候怎么刷新方向呢》????
  • 秘制鸭腿:present出来的控制器偶发性的不旋转, 下面一块是黑的, 返回后也是错乱的, 但是按了home键再进入即可恢复, 请问有什么好的解决办法吗
    bdada38a6732:我也出现了这个问题,请问解决了吗
    秘制鸭腿:@依稀一米 暂时无法解决, 我发现很多应用有类似情况 , 建议将返回键放左边, 至少用户能够返回上一级
    ec202b212cc6:我也遇到了这个问题,请问你解决了吗?
  • 吴德馨:前辈 能否把 demo 发出来,我试着写了一遍,但是还是没有达到效果
    我爱WSP:我在横屏的时候强制成竖屏,然后把手机调整到横屏这时候在点横屏按钮的时候获取device的方向还是之前设置的竖屏。。。楼主可知道原因。
    sfandy:@请问一个月 只提供思想,自己琢磨琢磨更靠谱些的。
  • codeing小牛:用作者的方法成功的解决了问题,不过底层是tababar 要在viewdidload 里选择一个默认的控制器 navigationcon 里viewdidload 方法里也要设置默认的支持方向和偏好方向否则就会报错
    ac6ff43241d6:@codeing小牛 现在这种方法,转屏的时候有时会卡,还有可能崩,你是怎么解决的???
    codeing小牛:@落翼之殇_8050 self.selectedIndex = 0 ; self 为自定制的tabar 对象 0 是默认选择第一个控制器 依次类推
    ac6ff43241d6:不过底层是tababar 要在viewdidload 里选择一个默认的控制器 ?? 怎么选择呢??
  • 下雨就好:博主,我按照你这么弄了,但是这个会导致我的原来的登陆页面直接崩溃,崩溃信息为-
    *** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'preferredInterfaceOrientationForPresentation must return a supported interface orientation!'
    *** First throw call stack:
    (
    0 CoreFoundation 0x0000000114e69e65 __exceptionPreprocess + 165
    1 libobjc.A.dylib 0x000000011452ddeb objc_exception_throw + 48
    2 CoreFoundation 0x0000000114e69d9d +[NSException raise:format:] + 205
    3 UIKit 0x0000000115b19199 -[UIViewController _preferredInterfaceOrientationForPresentationInWindow:fromInterfaceOrientation:] + 691
    4 UIKit 0x00000001162a56ce -[_UIFullscreenPresentationController _adjustOrientationIfNecessaryInWindow:forViewController:preservingViewController:] + 374
    5 UIKit 0x0000000115acc5d9 -[UIPresentationController _dismissWithAnimationController:interactionController:target:didEndSelector:] + 622
    6 UIKit 0x0000000115b128ee -[UIViewController _dismissViewControllerWithAnimationController:interactionController:completion:] + 569
    7 UIKit 0x0000000115b124aa -[UIViewController _dismissViewControllerWithTransition:from:completion:] + 995
    8 UIKit 0x0000000115b11a8c -[UIViewController dismissViewControllerWithTransition:completion:] + 1273
    9 UIKit 0x0000000115b117f3 -[UIViewController dismissViewControllerWithTransition:completion:] + 608
    10 UIKit 0x0000000115b10f2c -[UIViewController _performCoordinatedPresentOrDismiss:animated:] + 489
    11 UIKit 0x0000000115b144f1 -[UIViewController dismissViewContro
    sfandy:@下雨就好 对应的方向不对啊 ,preferredInterfaceOrientationForPresentation must return a supported interface orientation!'
  • 7e70e3784a48:你好,我用了你的方法成功实现了push的横屏。但是present出来的界面在dismiss时就会报错。不知道该怎么解决呢。应该是基类navigation抛出的错误
    sfandy:@flyiron :+1:
    7e70e3784a48:解决了,在基类navigationcontroller里的preferredInterfaceOrientationForPresentation和supportedInterfaceOrientations方法中判断self.topViewController是否是你要找的那个class,返回 [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];

    谢谢楼主!
    7e70e3784a48:present出来的界面是竖屏的uiimagepickerview,这个view是继承自uinavigationcontroll的,所以不能push
  • 小弱鸡:我在使用你的方法做强制横屏时,手动锁屏操作,然后返回上一个页面,UI位置完全乱套,有什么方案解决么?
    sfandy:@DeepWater 检查下对应的navigation方向是否对应了吧
  • 47200923d724:[self forceOrientationPortrait];
    这个是什么方法啊 楼主~~~我也遇到强制横竖屏的问题了~~~
    47200923d724:@sfandy
    楼主,你有没有试过模拟测试的时候,一进入app,本来是竖屏的,但是显示出来是横着的屏幕,竖着的画面,然后下面那一板块是黑的
    47200923d724:@sfandy 嘿嘿😜不好意思 我再斟酌斟酌~~~
    sfandy:@lin111111111 看下面好吧 :sweat:
  • 46684f2a32ec:大神,我用了你的方法,实现手动控制横竖屏了,现在问题来了,我在某个控制器中模态弹出系统的相片选择控制器,选择完,走到dismiss方法的时候就崩溃了,请教哈怎么解决,或者模态弹出一个系统导航包裹的控制器,dismiss的时候也会崩溃*** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'preferredInterfaceOrientationForPresentation must return a supported interface orientation!'
    46684f2a32ec:@liurang_major 崩溃的界面也不需要旋转屏幕,就是竖屏,大神,帮帮我指导下,比较急....
    sfandy:@liurang_major 你对应支持的旋转方向不对啊,没对应的啊。
    46684f2a32ec:大神,比较急,留个qq号,好联系你
  • 峰子1994:有demo吗
  • dd25f9257b81:谢谢 参考你的解决了自己的问题.
    sfandy:@AlaskuNull :+1:
  • lhq_cd:请教一下,我只想让我的App其中某个界面横屏,其他都是竖屏,应该怎么做呢,我用了你说的那两个强制横屏的方法,但是没用啊 ···是因为我没有勾选那个设置里需要支持横屏吗?但如果勾选了,不用实现方法也能实现横屏,但是这样所有的界面都可以横屏了啊?
    sfandy:@coderHQLee - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window; 这个方法就替换了勾选的操作了。
    sfandy:@coderHQLee 看看你的代码吧。这种方式就是处理某个界面横屏,其它竖屏问题的。

本文标题:iOS强制横屏总结

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