Martin

思想空间

我是Martin,iOS / Android 开发者。


欢迎来到我的思想空间

关于屏幕旋转的测试

swift 3 关于屏幕旋转的测试

开发中有这么个需求:主页面是竖屏显示,进入一个类似于播放视频的子页面需要横屏显示,退出到主页面,恢复竖屏

参考:小胖说swift11——– ios 进入某个VC强转为横屏,出VC后复原

下面记录实现过程:

首先创建项目,配置没做任何修改,基本结构如下:

pic1

在Appdelegate中添加代码:
var orientationPortrait = true  //记录是否为竖屏

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if self.orientationPortrait {
        return .portrait
    } else{
        return .landscapeRight
    }
}
在FirstViewController中添加代码:
override func viewWillAppear(_ animated: Bool) { //设置主页面竖屏
    super.viewWillAppear(animated)
    let value = UIInterfaceOrientation.portrait.rawValue
    (UIApplication.shared.delegate as! AppDelegate).orientationPortrait = true
    UIDevice.current.setValue(value, forKey: "orientation")
}
在SecondViewController中添加代码:
override func viewWillAppear(_ animated: Bool) { //设置子页面横屏
    super.viewWillAppear(animated)
    let value = UIInterfaceOrientation.landscapeRight.rawValue
    (UIApplication.shared.delegate as! AppDelegate).orientationPortrait = false
    UIDevice.current.setValue(value, forKey: "orientation")
}

override func viewWillDisappear(_ animated: Bool) { //返回主页面设置竖屏
    super.viewWillDisappear(animated)
    let value = UIInterfaceOrientation.portrait.rawValue
    (UIApplication.shared.delegate as! AppDelegate).orientationPortrait = true
    UIDevice.current.setValue(value, forKey: "orientation")
}

实现上述代码,基本实现了需求,但通过测试,发现一个问题:

重现方式如下:1:将手机的旋转锁定打开 -> 2:在竖屏情况打开APP -> 3:将手机横过来 -> 4:点击push进入second页面,发现second页面是竖屏的。
解决方法:

通过在Appdelegate的supportedInterfaceOrientationsFor方法中打断点分析: func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask 的触发方式有两种

一种是旋转手机时不定时触发(有时旋转会调用,有时不会):

一种是在调用UIDevice.current.setValue(value, forKey: “orientation”)时触发

修改SecondViewController的方法,打日志查看:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let value = UIInterfaceOrientation.landscapeRight.rawValue
    (UIApplication.shared.delegate as! AppDelegate).orientationPortrait = false
    let sysyemValue = UIDevice.current.value(forKey: "orientation")
    print("system value = \(sysyemValue)")
    print("setValue = \(value)")
    UIDevice.current.setValue(value, forKey: "orientation")
}

当正常操作是输出为:

system value = Optional(1)
setValue = 3

当重复上述的错误操作时,输出为:

system value = Optional(3)
setValue = 3

发现当当前sysyemValue与要设置的value相同时,不会触发 func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask

猜测 supportedInterfaceOrientationsFor 的触发方式类似于KVO(类似而已),即当orientation的值确实有变化时才会触发supportedInterfaceOrientationsFor

尝试手动调用KVO:

在viewWillAppear方法中添加:

UIDevice.current.willChangeValue(forKey: "orientation")
UIDevice.current.didChangeValue(forKey: "orientation")

然而并没有什么卵用,需要研究下swift的kvo,待续

在setValue前先设置一个其他值
UIDevice.current.setValue(UIInterfaceOrientation.unknown.rawValue, forKey: "orientation")
UIDevice.current.setValue(value, forKey: "orientation")

如此解决了上面的bug

项目代码

最近的文章

使用Mirror实现自定义对象转JSON及对象序列化

需求实现一个基类Model,继承它的类不需要再写代码即可实现对象转json即对象序列化实现效果如下基类为JSONModel,为了测试其健壮性,下面的例子写了一些嵌套关系创建一些类,继承JSONModel: //用户类 class User : JSONModel { var name:String = "" //姓名 var nickname:String? //昵称 var age:Int = 0 //年龄 var emails:[String]?...…

总结知识管理继续阅读
更早的文章

iOS开发tips

打log在 Xcode 的 Build Setting 中,在 Other Swift flags 的 Debug 栏中加入 -D DEBUG 即可加入一个编译标识。添加方法:/// 打log方法,release不会输出 ////// - Parameters:/// - message: log 文本/// - fileName: 文件名,有默认值/// - methodName: 方法名,有默认值/// - lineNumber: 行数,有默认值public func ...…

总结知识管理继续阅读