前言
经过了云课堂,公开课,中国大学mooc三种旋转需求的考(zhe)验(mo),也踩过了好多坑。虽然之前有写过一篇文章已经小结过一些问题,但现在再读,感觉还探讨地不够,故又补上一篇,希望能就此彻底做个了结。当然,也希望读过此文的童鞋能少走些弯路。。
注:此文提到的旋转包括页面和状态栏
正题
3种需求
3个app的旋转需求实现难度可以说是从易到难。
云课堂
云课堂的需求和实现最简单。相信大部分的app都是这个需求。
需求:进入播放页面默认横屏,同时支持页面自动旋转。
实现:因为是基于设备的系统事件通知来让页面响应旋转,所以关键是只要设置好- (BOOL)shouldAutorotate
、- (NSUInteger)supportedInterfaceOrientations
、- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
等几个函数即可。
公开课
公开课的需求和实现较云课堂来说要求要高一些。
需求:旋转的控制交给用户选择,而不是受系统控制。
实现:属于要无视设备的系统事件通知强制让页面旋转,具体可以参看前文
中国大学mooc
中国大学mooc的要求最高,是上述两种情况的结合体
需求:
进入播放页面默认横屏,同时支持页面自动旋转;
页面旋转不受系统自带的竖排锁定按钮控制,但是用户可以锁定旋转方向。
实现:
本质上来讲,它的实现是公开课方案的加强版。同样要无视设备的系统事件,而且是基于自定义的设备事件通知页面强制旋转。
强制旋转方式同公开课,但是实际开发过程中未遇到前文提到的需要强制把transform和frame的动画拆到两个animate block的问题,囧rz。。。关于自定义设备旋转通知,利用core motion来检测计算,具体代码是基于网上找的某段代码改的(抱歉忘了原作者是谁。。),代码查看请猛击这里。
一个坑引发的系列惨案
前面概述了我经历过的一些开发需求,下面重点讲一下我在开发过程中遇到的一个坑。
坑
相信开发过强制旋转的童鞋,应该都遇到过这么一个令人抓狂的问题:
原本在iOS8之前都是运行正常的代码,在iOS 8上运行强制旋转过后,屏幕的部分区域不能响应你的touch(没错,就是有些区域的按钮不能点了。。)。情况如图(别人画的):
在stackoverflow上一搜,也可以搜出一堆,比如这个,这个,还有这个。
一度也怀疑是否是自己的代码哪里写的不对。直到官方贴出iOS 8.3的这个升级说明,基本可以确信这个是iOS 8.3以前的系统bug(iOS 8 bug好多?!也难怪iOS 9要专注于系统稳定性和优化)
那么,直接用iOS 8以前的代码,在iOS8.3之后的系统上是不是直接运行也就没有问题了呢?答案是否定的。因为iOS 8以前,window的frame和StatusBarOrientation无关,始终都是Portrait的,但是iOS 8以后window的frame和StatusBarOrientation有关,会随着StatusBarOrientation的变化而变化。如果你用到了window的frame,那么必然还是会有影响的。
这里我做了一个demo,大家可以在iOS(-∞,8), [8, 8.3), [8.3, +∞)这三种情况的系统上运行一下,体会一下这个坑。。。
思路
既然知道坑的存在,那么又该如何解决呢?
A模式(window-viewController-view)
一般来说,待旋转的页面往往在window(无论是默认的window,还是你自己创建的window)下某个viewController内,而上述的bug也是发生在这种情况下。
B模式(window-view)
偶然的一次搜索让我看到这个帖子,有人提到直接把待旋转的页面
addSubview
到window中(注:不要设置rootViewController),可以避免出现上述的bug。我在demo中试了一下确实如此,然而遗憾的是,该方案反而会在[8.3, +∞)的系统上出现点击区域不全的问题。。。
总之,我表示目前我还找不到一个简单的通用方法。。以下是我觉得设计代码时,可以考虑的思路
也就是说,保证强制旋转可行性的问题,是在保证全部区域可点的前提下,同时考虑是否要需要旋转状态栏的问题。要根据实际需求,针对不同的系统版本写兼容性代码。
连锁反应
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
的影响。A模式下旋转页面和状态栏。如果是整个viewController被present,那么它在dimiss前,要保证状态栏的方向和- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
一致,否则在[8, 8.3)会发现dismiss后presentingViewController的方向会受影响。可以在demo试试哦+_+- alert view的展示和状态栏的方向有关。如果你仅需要旋转页面而不转状态栏只是隐藏,那么在A模式下旋转了页面后,alert view的展示会是个问题。
- 如果alert view是定制的,那么请同时考虑1,2问题所带来的影响。对于前者,取决于你的alert view是否需要支持
preferredInterfaceOrientationForPresentation
;对于后者,你要让你的alert view判断好它所处的当前viewController的真实展示方向,不能简单通过状态栏判断哦。
总结
要想获得旋转问题(尤其是强制旋转)的完美解决,目前我觉得需要一定的开发成本,所以应该需要根据需求做出一点取舍吧^_^
参考资料
2) http://forum.unity3d.com/threads/problem-with-changing-screen-orientation.274056/