【问题标题】:iOS 8 / 7 UIWindow with UIWindowLevelStatusBar Rotation issueiOS 8 / 7 UIWindow 与 UIWindowLevelStatusBar 旋转问题
【发布时间】:2015-01-14 14:08:47
【问题描述】:

我正在尝试添加具有UIWindowLevelStatusBar 级别的 UIWindow。它可以在 ipad 上完美地以纵向模式工作,但是在旋转设备后它就搞砸了。

在 iOS 7.x 上,所有旋转都很好,除了倒置,在 iOS 8.x 上,只有纵向模式很好,所有其他方向都搞砸了。知道如何解决吗?

CGRect frame = [UIApplication sharedApplication].statusBarFrame;
self.statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, 20)];

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect frame = [UIApplication sharedApplication].statusBarFrame;
CGAffineTransform test = [self transformForOrientation:orientation];

[self.statusWindow setWindowLevel:UIWindowLevelStatusBar];
[self.statusWindow setHidden:NO];


- (CGAffineTransform)transformForOrientation:(UIInterfaceOrientation)orientation
{
 switch (orientation)
 {
    case UIInterfaceOrientationLandscapeLeft:
        return CGAffineTransformMakeRotation(-DEGREES_TO_RADIANS(90.0f));

    case UIInterfaceOrientationLandscapeRight:
        return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90.0f));

    case UIInterfaceOrientationPortraitUpsideDown:
        return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(180.0f));

    case UIInterfaceOrientationPortrait:
    default:
        return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0.0f));
}
}

【问题讨论】:

  • 这是一种高度随机的方式来处理方向支持。您甚至根本不应该考虑转换任何东西,因为只要您正确设置了 rootViewController 属性,UIWindow 就可以并且将为您处理所有事情。
  • 您的代码中缺少某些内容,显示与您的 statusWindow 相关的所有代码。
  • 为澄清起见,此代码将在状态栏上设置另一个 uiwindow。所以没有rootviewcontroller。如果我不转换 uiwindow 保持纵向模式并且不会在 iOS 7 和 iOS 8 上旋转,因此必须手动旋转。如果您知道更好的方法,请分享。

标签: ios uiwindow


【解决方案1】:

在你的 UIWindow 子类的 init 方法中,观察这个通知:

// Rotation Notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil];

self.baseT = self.transform;

然后是方法本身:

- (void)didChangeOrientation:(NSNotification *)n
{

    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            self.transform = CGAffineTransformRotate(self.baseT, 0);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            self.transform = CGAffineTransformRotate(self.baseT, M_PI);
            break;
//      Home button on left
        case UIInterfaceOrientationLandscapeLeft:
            self.transform = CGAffineTransformRotate(self.baseT, -M_PI_2);
            break;
        case UIInterfaceOrientationLandscapeRight:
            self.transform = CGAffineTransformRotate(self.baseT, M_PI_2);
            break;
        default:
            self.transform = CGAffineTransformMakeRotation(0);
            break;
    }
}

根据您的实施,您可能还必须确保框架不会改变。另外,在 Class 的 dealloc 方法中,停止监听通知。

【讨论】:

  • 旋转确实有效,但 uiwindow 没有根据屏幕方向正确定位和调整大小。无论如何,感谢您的努力。
【解决方案2】:

作为对@dezinezync 答案的修改:如果将其放在视图控制器的willRotateToInterfaceOrientation 方法中,执行旋转会更好。这样,只有当设备旋转到应用程序构建设置的 General -> Deployment Info 部分中指定的受支持方向之一时,才会应用旋转。作为额外的奖励,您可以访问旋转动画的持续时间。只需确保您在视图控制器中引用了模态窗口即可。

只要屏幕方向发生变化,无论支持什么方向,都会触发UIDeviceOrientationDidChangeNotification 通知。这可能会导致不良行为。

这是一个例子:

UIWindow *modalWindow;

// Initialize your modal window somewhere in your code
// ...

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    // Make sure the modalWindow exists
    if (modalWindow != nil)
    {
        // Animate the modal window's rotation
        [UIView animateWithDuration:duration animations:^{
            [self rotateModal:modalWindow];
        }];
    }
}

- (void)rotateModal:(UIWindow*)window
{

    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            window.transform = CGAffineTransformRotate(self.baseT, 0);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            window.transform = CGAffineTransformRotate(self.baseT, M_PI);
            break;
//      Home button on left
        case UIInterfaceOrientationLandscapeLeft:
            window.transform = CGAffineTransformRotate(self.baseT, -M_PI_2);
            break;
        case UIInterfaceOrientationLandscapeRight:
            window.transform = CGAffineTransformRotate(self.baseT, M_PI_2);
            break;
        default:
            window.transform = CGAffineTransformMakeRotation(0);
            break;
    }
}

我刚刚在一个仅限横向的应用程序上做了类似的事情,我终于通过将所有内容移至 willRotateToInterfaceOrientation 方法使其正常工作。

【讨论】:

    【解决方案3】:

    iOS8 的解决方案(也需要如上所示的转换):

    UIScreen *screen = [UIScreen mainScreen];
    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
    if ([screen respondsToSelector:@selector(fixedCoordinateSpace)])
    {
        [self setFrame:[screen.coordinateSpace convertRect:statusBarFrame toCoordinateSpace:screen.fixedCoordinateSpace]];
    }
    

    但它不适用于 iOS9 测试版。

    【讨论】: