iOS学习笔记(3)— 屏幕旋转

一、屏幕旋转机制: 

  iOS通过加速计判断当前的设备方向和屏幕旋转。当加速计检测到方向变化的时候,屏幕旋转的流程如下:

  1、设备旋转时,系统接收到旋转事件。

  2、系统将旋转事件通过AppDelegate通知当前的主Window。

  3、window通知它的rootViewController。

    4、rootViewController判断所支持的旋转方向,完成旋转。

  iOS系统中屏幕旋转事件没有像触碰事件那样进行hitTest,所以只有rootViewController才能接收到屏幕旋转的事件,在其他viewController中实现旋转控制方法是不会被调用的。当屏幕旋转时应用程序会发出UIDeviceOrientationDidChangeNotification通知,这样任何关系方向变化的view都可以通过注册该通知,在设备方向发生变化的时候发生响应。

 

 

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

 

  1、首先判断当前viewController是否支持旋转到目标方向,如果支持则继续,否则流程就此结束。

 

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

 

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

 

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

 

  5、执行屏幕旋转动画。

 

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

 

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

 

 

  

 

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

二、旋转机制实现

 

 

  iOS5屏幕旋转控制

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return YES;
}

  返回YES就是允许旋转,NO就是不允许

  根据toInterfaceOrientation 可以控制屏幕允许旋转的方向,比如不支持Home按钮朝上这种屏幕方向。代码如下:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
   if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
    {
        return NO;
    }
    return YES;
}

  

  这种方法已经被苹果列为deprecated。但为了兼容iOS5及以前的版本还需要继续实现。

 

  iOS6屏幕旋转控制

  - (BOOL)shouldAutorotate  默认返回YES,当为YES时允许转屏,否则为不允许。

  - (NSUInteger)supportedInterfaceOrientations 决定可以转哪个方向。如果所有方向都支持返回 UIInterfaceOrientationMaskAll,如果不允许Home键朝上返回UIInterfaceOrientationMaskAllButUpsideDown。

 

三、注意事项

  1、旋屏后的frame

  如果直接把window.rootviewController = (UIViewController*)vc;旋屏的时候vc的frame一直都是保持竖屏状态,bounds是正确的。
  如果使用UINavigationController的rootviewControoler 设置为vc,然后那NavigationControllerView去作为window的rootView,在旋屏的时候会发现vc的frame和bounds都是正确的。
  结论:判断屏幕尺寸用bounds比frame更准确。
 
  2、如果viewController或者view是隐藏状态的话就接收不到屏幕旋转事件,那么重新显示就会有问题。可以通过 viewWillAppear 函数解决这个问题。
  3、屏幕旋转的时候,让界面暂时不响应事件。
  4、对于view层级比较复杂的视图,使用截图替换当前的视图,旋转完成后再替换回原来的视图。
  5、旋转后调用tableview的reload方法,保证屏幕尺寸变化后cell可以充满全屏。
posted @ 2013-07-17 14:01  挽弓挽长  阅读(1704)  评论(1编辑  收藏  举报