iOS8 对页面的旋转机制做了一些改变,这些改动也带来了不少问题。
本文介绍三个已经发现的问题,并尝试给出解决方案。
问题一:页面的旋转动画执行过程中dismiss,会让底下的不可旋转页面发生旋转。
先看一下这个bug的Qzone截图:
“动态” 这个页面,是不支持横屏的,但是却还是被系统旋转了。
此时,已经按照屏幕宽度创建好的视图自然不能拓展到充满屏幕。
接下来我们讨论一下重现的步骤。
- 首先,准备阶段,手机不锁定屏幕方向。页面A不可旋转,页面B可旋转,手机竖屏状态下,A present B。
- 接着,复现阶段。dismiss B,同时旋转手机到横屏。
- 最后,看现象。页面B发生了旋转,同时页面B消失,A页面也发生了旋转。
如果没有出现问题,可能要多试几次,这里的同时比较难,本质是要让页面发生旋转动画的时候,触发dismiss逻辑。
以下是苹果自家App,Apple Store的截图,10月6日的版本,该版本的改动是兼容iOS8 。
以下是手机QQ 10月8日更新的版本。
影响面:
在用户那里出现这个bug的概率有点低,但是还是存在一定量。
并且一旦出现,所有假设自己一定在竖屏状态下工作的页面都会出问题。
因为此时页面的宽度其实是手机屏幕的高度。假如某一些控件创建时依赖了页面的宽度,那么可能回到竖屏的时候表现异常,由于假设了一定在竖屏状态下工作,所以该页面也当然不会处理转屏的情况。
解决方法:
简而言之,dismiss的时候,让页面不可旋转;页面旋转的时候,不让用户触发 dismiss。就可以了。
问题二:屏幕横屏时,UIScreen 的宽高会发生变化
iOS 8 已经没有屏幕旋转的概念,只有屏幕大小变化的概念,详细看 WWDC 2014。
也就是说,在 iOS 8 上,当页面横屏的时候,不会收到屏幕旋转的通知,而是会收到屏幕大小改变的通知。
并且,此时 UIScreen 和 UIWindow 的宽高都会发生变化。
以下是 iOS 8 横屏时的视图树:
1 | <UIWindow: 0x178d2320; frame = (0 0; 568 320);> |
注意宽高已经相反了,对比同样情况下的 iOS 7 的视图树:
1 | <UIWindow: 0x79e59460; frame = (0 0; 320 568);> |
仔细看看会发现,iOS 7 的屏幕没有变化,通过中间的 ContainerView 加上 transform 来达到下层视图的旋转。
这种改变会带来什么样的后果的呢?
答案是,所有依赖屏幕宽高来创建的视图或者布局信息都会出问题,因为宽度随时都会变化。
截一个Qzone的Feed图片:
这里的文字排版,超出了屏幕的宽。
重现步骤如下:弱网络,上拉加载更多时,随便点击一张图片进图片浮层并横屏。
等待后面 Feed 接收完毕并进行排版,此时排版取的宽度,会是手机屏幕的高度。
排版完成后,从浮层回来,Feed 内容就超出屏幕的宽度了。
并且这个错误的排版会一直保持,除非触发再次排版。
解决方法是,取宽度的时候不要直接去屏幕宽度,而是 先判断屏幕方向,竖屏去宽度,横屏取高度。
问题三:同一个导航栏中横屏界面 pop 出竖屏界面的时候,动画异常。
第三个问题比较复杂,iOS8改了横屏界面 pop 竖屏界面的动画,跟iOS 7 有点不同。
具体实现移步 iOS8 导航栏横屏页面弹出竖屏页面的实现,
目前还没有找到好的解决方法,直接换成 present 规避之。
或者可以尝试一下自定义动画,有兴趣的可以尝试一下。