美文网首页
iOS 横竖屏切换问题

iOS 横竖屏切换问题

作者: 一半晴天 | 来源:发表于2018-03-01 15:52 被阅读154次

    首先介绍一下大的背景,我们的应用同时支持 iPad 和 iPhone 的 Universal App。在 iPhone 下我们的应用是一竖屏应用。在 iPad 自然是横竖屏都支持的。
    最近开发的一个小页面要求是横屏的,所以在 iPhone 上我们应用主要是竖屏但是有一些页面要求是横屏的。

    iPad 上支持横竖屏,和iPhone 限定竖屏的实现

    首先我们应用是一个同时支持 iPad 和 iPhone 应用。但是在 iPhone 是只支持竖屏的。所以基本的配置是这样做的。

    1. Info.plist 的 Deployment Info 下的 Device Orientation 是这样配置的。
        <key>UISupportedInterfaceOrientations</key>
        <array>
            <string>UIInterfaceOrientationPortrait</string>
            <string>UIInterfaceOrientationPortraitUpsideDown</string>
            <string>UIInterfaceOrientationLandscapeLeft</string>
            <string>UIInterfaceOrientationLandscapeRight</string>
        </array>
    
    1. AppDelegate 中实现下面的接口
    optional func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
    

    此接口的说明如下:

    This method returns the total set of interface orientations supported by the app. When determining whether to rotate a particular view controller, the orientations returned by this method are intersected with the orientations supported by the root view controller or topmost presented view controller. The app and view controller must agree before the rotation is allowed.

    If you do not implement this method, the app uses the values in the UIInterfaceOrientation key of the app’s Info.plist as the default interface orientations.

    具体实现如下:

      func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        let device = UIDevice.current
        switch device.userInterfaceIdiom {
        case .phone:
            return [.portrait]
        case .pad:
          return UIInterfaceOrientationMask.all
        default:
          return [.portrait]
          
        }
      }
    

    iPhone 上部分页面支持横屏的实现

    首先这个需要横屏的页面(MyLandscapeViewController)是通过 present 的方式来程现的。

    1. 重写 需要横屏的UIViewControllersupportedInterfaceOrientations 属性。 同时也明确的将 shouldAutorotate 返回 true 。虽然此方法默认返回
      true,因为只有此方法返回 true ,supportedInterfaceOrientations 方法才会调用。即:
           override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
            if UIDevice.isIpad{
                return super.supportedInterfaceOrientations
            }else{
                return UIInterfaceOrientationMask.landscape
            }
        }
      
        override var shouldAutorotate: Bool{
            return true
        }
    
    1. 修改 application:supportedInterfaceOrientationsFor: 接口 在 iPhone 上的返回。
      func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    
    
        let device = UIDevice.current
        switch device.userInterfaceIdiom {
        case .phone:
            var presentedVC = application.keyWindow?.rootViewController
            while let pVC = presentedVC?.presentedViewController{
                presentedVC = pVC
            }
            
            let fullscreenSupportedVC = ["MPInlineVideoFullscreenViewController", "MPMoviePlayerViewController", "AVFullScreenViewController","NSKVONotifying_AVFullScreenPlaybackControlsViewController","UIAlertController"
            ]
            if let pVC = presentedVC{
                let vcName = simpleClassName(pVC.classForCoder)
                if pVC is MyLandscapeViewController{
                    return UIInterfaceOrientationMask.allButUpsideDown
                }else if fullscreenSupportedVC.contains(vcName){
                    return UIInterfaceOrientationMask.allButUpsideDown
                }else{
                    return [.portrait]
                }
            }
            return [.portrait]
        case .pad:
          return UIInterfaceOrientationMask.all
        default:
          return [.portrait]
          
        }
      }
    

    系统在显示MyLandscapeViewController 时会通过取 Info.plist 或 上面
    AppDelegate 的 返回的结果取交集来确定需要 VC 需要的方向及是否需要旋转。显然他们的交集在 iPhone 上是 landscape。 于是在 iPhone 上,进入MyLandscapeViewController 页面时会自动旋转到横屏。

    常见问题的处理

    1. UIApplicationInvalidInterfaceOrientation

    Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and [PokerFury.NiuNiuGameWebViewController shouldAutorotate] is returning YES'

    比如在上面的横屏页面再打开其他竖屏的页面可能就会导致上面的错误。
    比如在此使用系统分享会打开 UIActivityViewController 就会报错。那么一种办法就是将可能需要打开的 ViewController 的名称的列表添加时上面支持的列表。

    然后上面的 fullscreenSupportedVC 列表修正如下:

            let fullscreenSupportedVC = ["MPInlineVideoFullscreenViewController", "MPMoviePlayerViewController", "AVFullScreenViewController","NSKVONotifying_AVFullScreenPlaybackControlsViewController",
                                         "UIAlertController","UIActivityViewController","SLComposeViewController"
            ]
    

    还有一个优化方向就是,因为可能不方便穷举上面的这种 VC,那么可以在横屏VC 实例化时设置一个标志变量(在 dealloc 时重置),如果此标志变量为 true 那就返回UIInterfaceOrientationMask.allButUpsideDown

    1. 从横屏页面退出应用没有切换回竖屏的问题。
      一般可以通过在应用的 RootVC 中实现下面的代码来处理。
        override var shouldAutorotate: Bool{
            return true
        }
        
        override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
            if UIDevice.isIpad{
                return super.supportedInterfaceOrientations
            }else{
                return [.portrait]
            }
        }
    

    UIViewController. supportedInterfaceOrientations 接口的说明如下:

    When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window. If the view controller supports the new orientation, the window and view controller are rotated to the new orientation. This method is only called if the view controller's shouldAutorotate method returns true.

    Override this method to report all of the orientations that the view controller supports. The default values for a view controller's supported interface orientations is set to all for the iPad idiom and allButUpsideDown for the iPhone idiom.

    The system intersects the view controller's supported orientations with the app's supported orientations (as determined by the Info.plist file or the app delegate's application(_:supportedInterfaceOrientationsFor:) method) to determine whether to rotate.

    相关文章

      网友评论

          本文标题:iOS 横竖屏切换问题

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