自定义UIWindows在iOS 8中无法正确旋转

时间:2014-11-03 00:14:02

标签: ios objective-c ios8 uiwindow

让您的应用程序进入横向模式并执行以下代码:

UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
toastWindow.hidden = NO;
toastWindow.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.5f];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [toastWindow removeFromSuperview];
});

在iOS 7中,您将在整个屏幕上方获得透明的蓝色覆盖,并在5秒后消失。在iOS 8中,您将获得覆盖屏幕一半以上的透明蓝色覆盖

device screenshot

这显然与Apple在iOS 8中所做的改变有关,其中屏幕坐标现在面向接口而不是面向设备,但在真正的Apple时尚中,它们似乎在横向模式和旋转方面留下了无数的错误。 / p>

我可以通过检查设备方向是否为横向并翻转主屏幕边界的宽度和高度来“修复”这一点,但这似乎是一个可怕的黑客攻击,当Apple在iOS 9中再次更改所有内容时将会破坏。 / p>

CGRect frame = [[UIScreen mainScreen] bounds];

if (UIInterfaceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
    frame.size.width = frame.size.height;
    frame.size.height = [[UIScreen mainScreen] bounds].size.width;
}

UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:frame];
toastWindow.hidden = NO;
toastWindow.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.5f];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [toastWindow removeFromSuperview];
});

有没有人遇到过这个问题,遇到了一个更好,更不易解决的问题?

编辑:我知道我可以使用UIView并将其添加到关键窗口,但我想在状态栏上放置一些内容。

4 个答案:

答案 0 :(得分:26)

您的“修复”因其他原因而不是很好,因为它实际上并不会旋转窗口,因此文本和其他子视图会以适当的方向显示。换句话说,如果您想要使用其他子视图增强窗口,它们的方向将不正确。

...

在iOS8中,您需要设置窗口的rootViewController,并且rootViewController需要从'shouldAutoRotate'和'supportedInterfaceOrientations'返回适当的值。关于此问题还有更多内容:https://devforums.apple.com/message/1050398#1050398

如果您的窗口没有rootViewController,那么您实际上是在告诉框架该窗口永远不应该自动转换。在iOS7中,这并没有什么区别,因为无论如何框架都没有为你做这项工作。在iOS8中,框架正在处理旋转,并且当它限制窗口的边界时,它认为它正在执行您所请求的内容(通过使用nif rootViewController)。

试试这个:

@interface MyRootViewController : UIViewController
@end

@implementation MyRootViewController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

- (BOOL)shouldAutorotate
{
    return YES;
}

@end

现在,在实例化后将rootViewController添加到窗口中:

UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
toastWindow.rootViewController = [[MyRootViewController alloc]init];

答案 1 :(得分:3)

我相信你必须转换UICoordinateSpace

在iPhone 6 Plus上,应用程序现在已经可以横向启动了,这使我正在处理的应用程序混乱,因为它只支持大多数应用程序的纵向方向,除了一个屏幕(意味着它需要支持横向方向)的plist)。

修复此问题的代码如下:

self.window = [[UIWindow alloc] initWithFrame:[self screenBounds]];

并使用以下代码计算边界:

- (CGRect)screenBounds
{
    CGRect bounds = [UIScreen mainScreen].bounds;
    if ([[UIScreen mainScreen] respondsToSelector:@selector(fixedCoordinateSpace)]) {
        id<UICoordinateSpace> currentCoordSpace = [[UIScreen mainScreen] coordinateSpace];
        id<UICoordinateSpace> portraitCoordSpace = [[UIScreen mainScreen] fixedCoordinateSpace];
        bounds = [portraitCoordSpace convertRect:[[UIScreen mainScreen] bounds] fromCoordinateSpace:currentCoordSpace];
    }
    return bounds;
}

希望这会引导你朝着正确的方向前进。

答案 2 :(得分:1)

在iOS 7及更早版本中,UIWindow的坐标系没有旋转。在iOS 8中它确实如此。我猜测[[UIScreen mainScreen] bounds]提供的框架不会影响轮换,这可能会导致您所看到的问题。

您可以从appDelegate的当前关键窗口抓取该帧,而不是从UIScreen获取帧。

但是,您似乎并不真正需要UIWindow提供的功能。我想回应别人的反应。建议您为此目的使用UIViewUIViewUIWindow更通用,应该是首选。

答案 3 :(得分:0)

最好的办法是使用视图而不是windows:

  

大多数iOS应用程序在其生命周期内仅创建和使用一个窗口。此窗口横跨整个主屏幕[...]。但是,如果应用程序支持使用外部显示器进行视频输出,则可以创建另一个窗口以在该外部显示器上显示内容。所有其他窗口通常由系统

创建

但如果你认为你有合理的理由创建多个窗口,我建议你创建一个NSWindow的子类来自动处理大小。

另请注意,Windows使用大量RAM,特别是在3x视网膜屏幕上。拥有多个内存将减少应用程序其余部分在收到内存不足警告并最终被杀之前可以使用的内存量。