为什么不总是调用已注册的UIDeviceOrientationDidChangeNotification?

时间:2011-02-10 01:03:34

标签: cocoa-touch notifications orientation uitableview uidevice

我写了一个简单的视图控制器,它显示了一个模态弹出对话框。因为它创建了一个覆盖整个屏幕的新窗口,所以我添加了一个UIDeviceOrientationDidChangeNotification观察器,用于指出如何使用CGAffineTransformMakeRotation()旋转视图。它似乎有效。

主要是。缺点是我可以摆弄方向,让它最终横向或颠倒。查看this 18s video演示此问题。在调试中,似乎有时通知不会触发,或者至少不会调用正在侦听它的回调方法。

但是,我必须遗漏一些东西,因为如果再看一下视频,你会注意到它背后的视图 正确旋转。那个由-willAnimateRotationToInterfaceOrientation:duration:管理。如何正确地调用iOS控制器方法(可能由UIViewController中的UIDeviceOrientationDidChangeNotification观察者管理)但我自己的代码不是?

3 个答案:

答案 0 :(得分:12)

我在Kobo中使用了UIApplicationWillChangeStatusBarOrientationNotification,这似乎可以解决问题。它更加可靠,因为您希望匹配UI的选择方向,而不一定是设备恰好在哪里。换句话说,您可以让Apple决定何时应该重新定位窗口。

以下是iPad上Kobo应用程序的弹出对话框代码中的几个片段(UIAlertView在iPad上看起来很有点,所以Richard Penner写了一个更好的片段)。在更新的iOS版本出现一些故障并且不得不在不同情况下显示这些对话框(所有方向都是IIRC)之后,我不得不将其调整为直接位于UIWindow内部,这意味着要复制所有的方向转换逻辑。

此代码来自UIViewController,其视图直接删除到当前窗口。

- (void) presentDialogWindow
{
    // register for orientation change notification
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(orientationWillChange:)
                                                 name: UIApplicationWillChangeStatusBarOrientationNotification
                                               object: nil];
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(orientationDidChange:)
                                                 name: UIApplicationDidChangeStatusBarOrientationNotification
                                               object: nil];
}

- (void) orientationWillChange: (NSNotification *) note
{
    UIInterfaceOrientation current = [[UIApplication sharedApplication] statusBarOrientation];
    UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue];
    if ( [self shouldAutorotateToInterfaceOrientation: orientation] == NO )
        return;

    if ( current == orientation )
        return;

    // direction and angle
    CGFloat angle = 0.0;
    switch ( current )
    {
        case UIInterfaceOrientationPortrait:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationPortraitUpsideDown:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationLandscapeLeft:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                case UIInterfaceOrientationLandscapeRight:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
        case UIInterfaceOrientationPortraitUpsideDown:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationPortrait:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationLandscapeLeft:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                case UIInterfaceOrientationLandscapeRight:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
        case UIInterfaceOrientationLandscapeLeft:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationLandscapeRight:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationPortraitUpsideDown:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                case UIInterfaceOrientationPortrait:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
        case UIInterfaceOrientationLandscapeRight:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationLandscapeLeft:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationPortrait:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                case UIInterfaceOrientationPortraitUpsideDown:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
    }

    CGAffineTransform rotation = CGAffineTransformMakeRotation( angle );

    [UIView beginAnimations: @"" context: NULL];
    [UIView setAnimationDuration: 0.4];
    self.view.transform = CGAffineTransformConcat(self.view.transform, rotation);
    [UIView commitAnimations];
}

- (void) orientationDidChange: (NSNotification *) note
{
    UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue];
    if ( [self shouldAutorotateToInterfaceOrientation: [[UIApplication sharedApplication] statusBarOrientation]] == NO )
        return;

    self.view.frame = [[UIScreen mainScreen] applicationFrame];

    [self didRotateFromInterfaceOrientation: orientation];
}

我们通过加载此视图控制器,将其视图添加到窗口,然后调用-presentModalDialog来使用它,如下所示:

UIView *window = [[UIApplication sharedApplication] keyWindow];
[window addSubview: theController.view];
[theController presentDialogWindow];

我将很快创建一个简单的UIViewController子类来实现fiddly位,并将它发布在我的github帐户上。当我这样做时,我会编辑这个&链接到它。

答案 1 :(得分:0)

UIDeviceOrientation有一些值未映射到UIInterfaceOrientation:

UIDeviceOrientationUnknown,
UIDeviceOrientationFaceUp,              // Device oriented flat, face up
UIDeviceOrientationFaceDown             // Device oriented flat, face down

通知回调是否可能会被触发,但这些情况不会被处理?

如果视图控制器可以访问该窗口 - 它可以手动将didRotate回调转发到窗口。

答案 2 :(得分:0)

我通过取消UIDeviceOrientationDidChangeNotification的使用来解决这个问题。我所做的是创建UIViewController的子类,并将自定义视图设置为其视图。然后它只是实现-willAnimateRotationToInterfaceOrientation:duration:来进行旋转。这对我来说实际上是不那么挑剔的代码。但是,它确实感觉像是一个黑客,只是为了在UIViewController的克隆中利用自转来创建一个任意的presentModalViewController。似乎UIDeviceOrientationDidChangeNotification应该正常工作。我希望有一种方法可以让它表现出来,但我还没有找到它。 : - (