iOS8 转屏 Bug 汇总

iOS8 对页面的旋转机制做了一些改变,这些改动也带来了不少问题。
本文介绍三个已经发现的问题,并尝试给出解决方案。

问题一:页面的旋转动画执行过程中dismiss,会让底下的不可旋转页面发生旋转。

先看一下这个bug的Qzone截图:

“动态” 这个页面,是不支持横屏的,但是却还是被系统旋转了。
此时,已经按照屏幕宽度创建好的视图自然不能拓展到充满屏幕。
接下来我们讨论一下重现的步骤。

  1. 首先,准备阶段,手机不锁定屏幕方向。页面A不可旋转,页面B可旋转,手机竖屏状态下,A present B。
  2. 接着,复现阶段。dismiss B,同时旋转手机到横屏。
  3. 最后,看现象。页面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
2
3
4
5
6
7
<UIWindow: 0x178d2320; frame = (0 0; 568 320);>
| <UITransitionView: 0x17fe3180; frame = (0 0; 568 320);>
| | <UILayoutContainerView: 0x17fd6280; frame = (0 0; 568 320);>
| | | <UINavigationTransitionView: 0x17fdb4f0; frame = (0 0; 568 320);>

以及此时的屏幕大小如下:
<UIScreen: 0x15863810; bounds = { {0, 0}, {568, 320} }; mode = <UIScreenMode: 0x147be4a0; size = 640.000000 x 1136.000000>>

注意宽高已经相反了,对比同样情况下的 iOS 7 的视图树:

1
2
3
4
5
<UIWindow: 0x79e59460; frame = (0 0; 320 568);>
| <UILayoutContainerView: 0x7b18e140; frame = (0 0; 320 568); transform = [0, 1, -1, 0, 0, 0]; >
| | <UINavigationTransitionView: 0x7b17b390; frame = (0 0; 568 320); >

<UIScreen: 0x79e48cd0; bounds = { {0, 0}, {320, 568} }; mode = <UIScreenMode: 0x79fa0520; size = 640.000000 x 1136.000000>>

仔细看看会发现,iOS 7 的屏幕没有变化,通过中间的 ContainerView 加上 transform 来达到下层视图的旋转。

这种改变会带来什么样的后果的呢?
答案是,所有依赖屏幕宽高来创建的视图或者布局信息都会出问题,因为宽度随时都会变化。
截一个Qzone的Feed图片:


这里的文字排版,超出了屏幕的宽。
重现步骤如下:弱网络,上拉加载更多时,随便点击一张图片进图片浮层并横屏。
等待后面 Feed 接收完毕并进行排版,此时排版取的宽度,会是手机屏幕的高度。
排版完成后,从浮层回来,Feed 内容就超出屏幕的宽度了。
并且这个错误的排版会一直保持,除非触发再次排版。
解决方法是,取宽度的时候不要直接去屏幕宽度,而是 先判断屏幕方向,竖屏去宽度,横屏取高度。

问题三:同一个导航栏中横屏界面 pop 出竖屏界面的时候,动画异常。

第三个问题比较复杂,iOS8改了横屏界面 pop 竖屏界面的动画,跟iOS 7 有点不同。
具体实现移步 iOS8 导航栏横屏页面弹出竖屏页面的实现
目前还没有找到好的解决方法,直接换成 present 规避之。
或者可以尝试一下自定义动画,有兴趣的可以尝试一下。