这次又踩了一个坑, 虽然网上有很多解决方案, 但总是照葫芦画瓢, 导致实现出来问题百出, 后面查到 Programming iOS 11 书上的 306 页 Initial orientation 一节, 短短几句话就概括了正确的办法. 所以说, 还是要多看书啊.
APP 情况描述: 当前 APP 总体是标准的竖屏界面, 但在 APP 中有一个统计界面是横屏的, 且横屏状态下需要对设备旋转作出响应, 即可以左横屏或右横屏.
正确的实现方式如下:
-
在 APP 的 info.plist 中只设置允许旋转为 portait, 即设置只允许竖向显示.
错误显示
这个设置非常重要, 因为如果在 info.plist 中有其他方向设置的话, 每次当 APP 启动后, APP 会根据当前最接近的旋转方向来旋转屏幕, 如果主界面设计为竖屏的话, 则就会出现显示异常.
下面的图就是当手机横向放置的情况下打开 APP, 主界面设计为竖屏时候的错误显示:
-
在 APP Delegate 中实现如下方法, 指定允许的旋转方向:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return [.portrait, .landscapeLeft, .landscapeRight] }
其中的旋转方向设置为在 APP 中可能出现的旋转, 这里设计为竖屏, 以及左横屏和右横屏.
-
在每个独立的视图控制器中设置它们的旋转方向, 要注意的是, 容器控制器(比如导航控制器)的旋转设置会覆盖子控制器的设置, 故需要特殊处理.
APP 中 window 的根控制器正好是一个导航控制器, 在导航控制器中需要这样写:override var supportedInterfaceOrientations: UIInterfaceOrientationMask { let topVCRotate = self.topViewController?.supportedInterfaceOrientations return topVCRotate ?? .portrait } override var shouldAutorotate: Bool { let topVCRotate = self.topViewController?.shouldAutorotate return topVCRotate ?? false }
而导航控制器的子控制器中, 就直接设置旋转方向以及是否允许旋转即可.
这里是横屏界面的设置:override var shouldAutorotate: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return [.landscapeLeft, .landscapeRight] }
这里是竖屏界面的设置:
override var shouldAutorotate: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
通过上述设置, 就解决了在一个 APP 中单独某些界面支持不同方向的旋转以及是否允许某些界面可以旋转.
上述只是针对单个页面显示时候的解决方法. 但是有一种特殊情况, 比如页面 A 设计为横屏, 页面 B 设计为竖屏, 当从页面 A 返回到页面 B, 此时 B 页仍然会显示为横屏. 这样的情况下, 就需要特殊处理.
新建一个方法:
func changeToPreferredOrientation(orientation: UIInterfaceOrientation) {
let orUnknown = NSNumber(value: UIInterfaceOrientation.unknown.rawValue)
UIDevice.current.setValue(orUnknown, forKey: "orientation")
let rotatePreferred = NSNumber(value: orientation.rawValue)
UIDevice.current.setValue(rotatePreferred, forKey: "orientation")
}
代码中的前面两行是为了绕过一个苹果坑必须添加的...
在 viewWillAppear
中调用它即可. 不过要注意的是, 这个方法要能达到效果, 还有一个条件, 即将视图控制器的 shouldAutorotate
属性重写为返回 true
.
网友评论