加速计是整个IOS屏幕旋转的基础,依赖加速计,设备才可以判断出当前的设备方向,IOS系统共定义了以下七种设备方向:

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
};

  以及如下四种界面方向:

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
};
 

一、UIKit处理屏幕旋转的流程 

  当加速计检测到方向变化的时候,会发出 UIDeviceOrientationDidChangeNotification 通知,这样任何关心方向变化的view都可以通过注册该通知,在设备方向变化的时候做出相应的响应。

  UIKit的相应屏幕旋转的流程如下:

1、设备旋转的时候,UIKit接收到旋转事件。

2、UIKit通过AppDelegate通知当前程序的window。

3、Window会知会它的rootViewController,判断该view controller所支持的旋转方向,完成旋转。

4、如果存在弹出的view controller的话,系统则会根据弹出的view controller,来判断是否要进行旋转。

二、UIViewController实现屏幕旋转

  在响应设备旋转时,我们可以通过UIViewController的方法实现更细粒度的控制,当view controller接收到window传来的方向变化的时候,流程如下:

1、首先判断当前viewController是否支持旋转到目标方向,如果支持的话进入流程2,否则此次旋转流程直接结束。

2、调用 willRotateToInterfaceOrientation:duration: 方法,通知view controller将要旋转到目标方向。如果该viewController是一个container view controller的话,它会继续调用其content view controller的该方法。这个时候我们也可以暂时将一些view隐藏掉,等旋转结束以后在现实出来。

3、window调整显示的view controller的bounds,由于view controller的bounds发生变化,将会触发 viewWillLayoutSubviews 方法。这个时候self.interfaceOrientation和statusBarOrientation方向还是原来的方向。

4、接着当前view controller的 willAnimateRotationToInterfaceOrientation:duration: 方法将会被调用。系统将会把该方法中执行的所有属性变化放到动animation block中。

5、执行方向旋转的动画。

6、最后调用 didRotateFromInterfaceOrientation: 方法,通知view controller旋转动画执行完毕。这个时候我们可以将第二部隐藏的view再显示出来。

  整个响应过程如下图所示:

  

  以上就是UIKit下一个完整的屏幕旋转流程,我们只需要按照提示做出相应的处理就可以完美的支持屏幕旋转。

三、注意事项和建议

  1)注意事项

  当我们的view controller隐藏的时候,设备方向也可能发生变化。例如view Controller A弹出一个全屏的view controller B的时候,由于A完全不可见,所以就接收不到屏幕旋转消息。这个时候如果屏幕方向发生变化,再dismiss B的时候,A的方向就会不正确。我们可以通过在view controller A的viewWillAppear中更新方向来修正这个问题。

  2)屏幕旋转时的一些建议

  • 在旋转过程中,暂时界面操作的响应。
  • 旋转前后,尽量保持当前显示的位置不变。
  • 对于view层级比较复杂的时候,为了提高效率在旋转开始前使用截图替换当前的view层级,旋转结束后再将原view层级替换回来。
  • 在旋转后最好强制reload tableview,保证在方向变化以后,新的row能够充满全屏。例如对于有些照片展示界面,竖屏只显示一列,但是横屏的时候显示列表界面,这个时候一个界面就会显示更多的元素,此时reload内容就是很有必要的。

  注:以上内容和插图全部来自苹果官方文档:View Controller Programming Guide for iOS

【转】IOS设备旋转的内部处理流程以及一些【优化建议】的更多相关文章

  1. Mac平台下部署UE4工程到iOS设备的流程

    1.开发环境 UE4.Xcode.iOS版本情况如下: 1.UE4:当前最新版本Unreal Engine 4.17.2. 2.Xcode:当前最新版本Xcode9.0. 3.iOS:当前最新版本iO ...

  2. 不通过App Store,在iOS设备上直接安装应用程序(转)

    今天在iOS设备上安装天翼云存储app,在safari上直接打开http://cloud.189.cn/wap/index.jsp,点击“点击免费安装”,如下图: 神奇的事情发生了,设备上直接下载ap ...

  3. 【转】使IFRAME在iOS设备上支持滚动

    原文链接: Scroll IFRAMEs on iOS原文日期: 2014年07月02日 翻译日期: 2014年07月10日翻译人员: 铁锚 很长时间以来, iOS设备上Safari中超出边界的元素将 ...

  4. 使IFRAME在iOS设备上支持滚动

    原文链接: Scroll IFRAMEs on iOS原文日期: 2014年07月02日 翻译日期: 2014年07月10日翻译人员: 铁锚很长时间以来, iOS设备上Safari中超出边界的元素将不 ...

  5. Samsung_tiny4412(驱动笔记03)----字符设备驱动基本操作及调用流程

    /*********************************************************************************** * * 字符设备驱动基本操作及 ...

  6. iOS设备的标识---UUID和IDFA

    一:1.1 :UDID 简介:UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成.在很多需要限制一台设备一个账 ...

  7. 怎样将游戏从Unity导到iOS设备上

    当我开始开发自己的iOS游戏时,我会考虑的第一件事便是如何将其导出到设备中,如此有效地测试我的游戏.最初,该过程看似很长且复杂,我所遇到的主要问题是,尽管存在许多资源,但是它们并非完全来自同样的地方, ...

  8. 分析Tapjoy的模式—分发用于ios设备的企业级应用程序

    下面简单介绍下Tapjoy的模式,供大家参考: Tapjoy最初的合作模式:“按安装奖励”(pay-per-install) Tapjoy利用非常成功的奖励性下载模式影响了App Store的免费游戏 ...

  9. 设备旋转,创建水平模式布局--Android studio

    1.在项目工具窗口中,右键单击res目录后选择new--Android resource directory菜单项. 2.从资源类型Resource type列表中选择layout,保持Source ...

随机推荐

  1. ES6 Promise 接口

    构造函数 new Promise(function(resolve, reject){}); 构造函数接受一个函数(executor)作为参数,该函数在返回 Promise 实例之前被调用.函数的两个 ...

  2. 去掉NSString中的HTML标签

    经常出现字符串带有html标签.下面有个方法一步到位去掉HTML标签 <span style="font-family: 'comic sans ms', sans-serif; co ...

  3. hibernate的多对多例子讲解(加图片)

    在hibernate中也有多对多的关系.但是这样关系执行的效率不高,所以我们可以通过两个多对1或者两个1对多来实现. 在现实生活中多对多的关系也比较常见.比如说老师和学生.一个老师有多个学生,一个学生 ...

  4. MongoDB 基础命令行

    本文专门介绍MongoDB的命令行操作.其实,这些操作在MongoDB官网提供的Quick Reference上都有,但是英文的,为了方便,这里将其稍微整理下,方便查阅. 登录和退出 mongo命令直 ...

  5. sublime text3 安装package

    在sublime text2中安装package control插件的时候是执行python: import urllib2,os; pf='Package Control.sublime-packa ...

  6. thread_AtomicBoolean

    Boolean值的变化的时候不允许在之间插入,保持操作的原子性 它提供了原子性操作,其中exists.compareAndSet(false, true)这个操作把比较和赋值操作组成了一个原子操作,中 ...

  7. 字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

    Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在 ...

  8. Orleans 之 监控工具的使用

    这一节,我们来说说orleans 中的几个实用工具,OrleansHost.OrleansCounterControl.OrleansManager.ClientGenerator. 1.Orlean ...

  9. 基于DevExpress开发的GridView如何实现一列显示不同的控件类型

    在很多DevExpress的使用例子里面,我们可以看到,基于GridView实现的不同控件展示的时候,每一列的控件类型都是一样的,如果我要某一列的一行让用户可以从下列列表选择选项,而其他行不可选择,那 ...

  10. sql分页存储过程

    ALTER PROCEDURE [dbo].[P_SplitPagesQuery] @TablesName NVARCHAR(MAX),--表名或视图名(只能传单一表名) @PK NVARCHAR(M ...