iOS Orientation一些事(不包括iOS6)

hikui posted @ 2012年9月12日 21:49 in iOS开发 , 4170 阅读

完整代码可在 gitcafe项目主页 中下载。

之前的一篇文章提到对iOS系统键盘的hack,其中有提到新版的东方财富通的数字键盘是自定义键盘。在新的需求里,个股搜索需要支持横屏,本人又比较懒,不想写代码一个键一个键的调frame,就想到了通过判断Orientation从xib载入不同的view直接贴上去。但是碰到了一个不小的问题。

因为代码是属于公司的,我不好直接拿出来贴。在这里我把问题简化地提出来:

如图有两个ViewController,设左边为A,右边为B。点击A时,把B push进navigationController。要求进入B时,如果画面为横屏,则在label显示landscape,如果是竖屏,则显示portrait。在B中,要随着设备的orientation变化,切换label显示landscape或者portrait。

 

一开始,我觉得这挺简单,只要在viewDidLoad中判断UIDeviceOrientation就可以了。于是写下了这样的代码:

A中:

 

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

B中:

 

- (void)viewDidLoad
{
    [super viewDidLoad];
    UILabel *label = (UILabel *)[self.view viewWithTag:1];
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    if (UIDeviceOrientationIsLandscape(orientation)) {
        label.text = @"landscape";
    }else{
        label.text = @"portrait";
    }
}

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

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    UILabel *label = (UILabel *)[self.view viewWithTag:1];
    if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
        label.text = @"landscape";
    }else{
        label.text = @"portrait";
    }
}

乍看起来好像挺正确的,怎么把玩都没问题。但是,一旦需求说,A不支持横屏,B支持。这时候问题就来了:

A改为:

 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

编译运行,在画面A的时候,就把模拟器设置成landscape:

这时,正如需求中要求的,A没有支持横屏。这是保持横屏的状态,点击push,则出现下面的画面:

可以看到,B虽然画面是竖屏的,但是label已经被改成landscape了。通过在ViewDidLoad和shouldAutorotateToInterfaceOrientation中设断点可以看到,UIDeviceOrientation是属于landscape的,而系统询问shouldAutorotateToInterfaceOrientation时,询问的是是否支持Portrait。这样两者值就不一样了。可见系统真正在渲染View的时候是按照Portrait来的,并不是根据UIDeviceOrientation来的,然而似乎没有一个方法来获得载入时UIInterfaceOrientation的办法。这个问题我一直没有找到办法去解决,或者即便测试测出来问题了,我也可以说,没有哪个傻逼是这么用手机的(事实上测试组一直没测试出这个BUG)。直到我今天看MBProgressHUD的代码时才直到UIInterfaceOrientation可以用一个看起来比较妖的办法来得到:

 

/*B中*/
- (void)viewDidLoad
{
    [super viewDidLoad];
    UILabel *label = (UILabel *)[self.view viewWithTag:1];
//    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
//    if (UIDeviceOrientationIsLandscape(orientation)) {
//        label.text = @"landscape";
//    }else{
//        label.text = @"portrait";
//    }
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (UIInterfaceOrientationIsLandscape(orientation)) {
        label.text = @"landscape";
    }else{
        label.text = @"portrait";
    }
}

这样一来,即便是那种变态的用法,也不会出现错误了。

除此之外我要说的是,我看到有些人把切换屏幕方向时,UI的变动都写在了shouldAutorotateToInterfaceOrientation方法里了,虽然也可以运行,但是只要变动比较复杂,可以看到很明显的动画延时。UI的变动应该写在willAnimateRotationToInterfaceOrientation才是,因为这个方法是运行在animation blocks里面的。shouldAutorotateToInterfaceOrientation应该只判断是否支持该屏幕方向。

創用 CC 授權條款
本著作係採用創用 CC 姓名標示 2.0 通用版 授權條款授權.

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter