iOS 6应用-如何处理iPhone 5屏幕尺寸?

265

可能是重复问题:
如何开发或迁移适用于iPhone 5屏幕分辨率的应用程序?

我想知道我们应该如何处理iPhone 5更大的屏幕尺寸。

由于它的高度有更多像素,使用坐标(并且仅将像素加倍以解决视网膜/非视网膜问题)的GCRectMake之类的东西在版本之间不会无缝工作,就像我们得到Retina时一样。

我们是否需要设计两个故事板,就像iPad一样?

我个人认为,苹果不会要求您每次绘制某些内容时都要检查屏幕大小,就像许多答案所说的那样。这在iPad上发生了吗?


16
只需添加一张名为Default.png并大小为4英寸的图片,你的应用程序即可立即占满整个4英寸屏幕。 - Pascal
2
虽然这可能有些违反直觉,但根据Pascal的建议,仅添加一个视网膜(4英寸)启动图像即可消除应用视图两侧的黑色区域,在视网膜-4和早期设备上均可实现全屏。 - Rich Apodaca
8个回答

209

据我所知,从今天的演示中可以看出,所有应用程序在垂直拉伸屏幕时将继续正常工作。它们将被加上黑边框或者说在高度上的额外的88个点将变成黑色。

如果你只打算支持iOS 6+,那么一定要考虑使用自动布局(Auto Layout)。它可以去除所有固定布局处理,并使用约束来布局。没有任何硬编码,你的生活会变得更简单。

但是,如果你需要支持旧版iOS,则真的取决于你的应用程序。大多数使用标准导航栏和/或选项卡栏的应用程序,可以简单地扩展中间的内容以利用那些额外的点。将中心内容的自动调整蒙版设置为在两个方向上扩展即可。

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

它对于表视图开箱即用非常出色,但如果您的应用程序使用像素完美布局来显示内容,那么最好的选择是重新设计内容,使其适应不同的高度。

如果这不可行,那么唯一剩下的选项就是拥有两个UI(适用于iPhone 5之前和iPhone 5)。

如果那听起来很丑陋,那么您可以采用默认的letterboxed模型,在其中额外的点/像素只会显示为黑色。

编辑

为了使您的应用程序能够与iPhone 5配合使用,您需要添加一个启动图像的视网膜版本。它应该被命名为Default-568h@2x.png。它必须是视网膜质量 - 这里没有向后兼容性 :)

您还可以从Xcode中选择此图像。转到目标,在“摘要”部分下找到“启动图像”。该图像的尺寸必须为640x1136像素。如果有帮助,以下是在哪里找到它的截图。

Xcode screenshot


1
我认为在非高 iPhone 上,UIActionSheet 在 iOS6 上存在问题,如果您使用此方法,并且没有采取任何特殊措施来修复操作表。如果我将我的主要 NIB 设置为高,则唯一出现问题的是这一点。 - Andrew Johnson
1
Xcode会将您的图像自动重命名为Default-568h@2x.png,因此您不必自己命名它。只需在Photoshop上制作一张640x1136的图片,然后将其拖放到项目中指定的区域即可。 - George Asda
6
您可以在-application:didFinishLaunchingWithOptions:方法的顶部添加self.window.frame = [UIScreen mainScreen].bounds; - Frank Schmitt
此外,如果视图包含子视图,则还需要将视图的autoresizesSubviews设置为YES。 - ldindu

84
你需要将一张640x1136像素的PNG图片(Default-568h@2x.png)添加为项目的4英寸默认启动图像,并且它将使用额外的空间(对于基于简单表格的应用程序而言没有太多的努力,游戏将需要更多的努力)。
我创建了一个小的UIDevice类别,以处理所有屏幕分辨率。你可以在这里获取代码,但代码如下:

文件UIDevice+Resolutions.h

enum {
    UIDeviceResolution_Unknown           = 0,
    UIDeviceResolution_iPhoneStandard    = 1,    // iPhone 1,3,3GS Standard Display  (320x480px)
    UIDeviceResolution_iPhoneRetina4    = 2,    // iPhone 4,4S Retina Display 3.5"  (640x960px)
    UIDeviceResolution_iPhoneRetina5     = 3,    // iPhone 5 Retina Display 4"       (640x1136px)
    UIDeviceResolution_iPadStandard      = 4,    // iPad 1,2,mini Standard Display   (1024x768px)
    UIDeviceResolution_iPadRetina        = 5     // iPad 3 Retina Display            (2048x1536px)
}; typedef NSUInteger UIDeviceResolution;

@interface UIDevice (Resolutions)

- (UIDeviceResolution)resolution;

NSString *NSStringFromResolution(UIDeviceResolution resolution);

@end

文件 UIDevice+Resolutions.m

#import "UIDevice+Resolutions.h"

@implementation UIDevice (Resolutions)

- (UIDeviceResolution)resolution
{
    UIDeviceResolution resolution = UIDeviceResolution_Unknown;
    UIScreen *mainScreen = [UIScreen mainScreen];
    CGFloat scale = ([mainScreen respondsToSelector:@selector(scale)] ? mainScreen.scale : 1.0f);
    CGFloat pixelHeight = (CGRectGetHeight(mainScreen.bounds) * scale);

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
        if (scale == 2.0f) {
            if (pixelHeight == 960.0f)
                resolution = UIDeviceResolution_iPhoneRetina4;
            else if (pixelHeight == 1136.0f)
                resolution = UIDeviceResolution_iPhoneRetina5;

        } else if (scale == 1.0f && pixelHeight == 480.0f)
            resolution = UIDeviceResolution_iPhoneStandard;

    } else {
        if (scale == 2.0f && pixelHeight == 2048.0f) {
            resolution = UIDeviceResolution_iPadRetina;

        } else if (scale == 1.0f && pixelHeight == 1024.0f) {
            resolution = UIDeviceResolution_iPadStandard;
        }
    }

    return resolution;
 }

 @end

以下是使用此代码的步骤:

1)将上述UIDevice+Resolutions.h和UIDevice+Resolutions.m文件添加到您的项目中

2)在您的ViewController.m文件中添加#import“ UIDevice + Resolutions.h”这一行

3)添加此代码以检查您正在处理哪些设备版本

int valueDevice = [[UIDevice currentDevice] resolution];

    NSLog(@"valueDevice: %d ...", valueDevice);

    if (valueDevice == 0)
    {
        //unknow device - you got me!
    }
    else if (valueDevice == 1)
    {
        //standard iphone 3GS and lower
    }
    else if (valueDevice == 2)
    {
        //iphone 4 & 4S
    }
    else if (valueDevice == 3)
    {
        //iphone 5
    }
    else if (valueDevice == 4)
    {
        //ipad 2
    }
    else if (valueDevice == 5)
    {
        //ipad 3 - retina display
    }

1
只是一些建议:1)在报告“iPhoneTallerHiRes”之前,您可能希望实际测试高度是否等于568 * 2;2)您可能还想测试宽度。然后,对于未明确识别的所有内容,请返回“UIDevice_notRecognizedRes”。如果将来的iPhone> 5或新的“新iPad”具有另一个屏幕大小,则应更容易适应。 - mvds
1
进一步推广这种逻辑,您可能还想明确检查 UIUserInterfaceIdiomPad 而不是假设 !phone == pad - mvds
批准了Evan Schoenberg的编辑请求,以修复iOS 4及更高版本上标准分辨率iPhone的行为。编辑后的代码位于malcommac的git存储库的分支中:https://github.com/evands/iOSUtilities/tree/main/UIDevice+Resolutions(将上下文移到注释中而不是问题本身) - Mu Mind
1
小心使用苹果已知的类前缀。 - Chris Wagner
@FatihArslan - 这不是你该使用这个函数的方式。这是不正确的 "[UIDevice currentResolution] == UIDevice_iPhoneTallerHiRes"。有人能告诉我如何正确地使用这个函数吗??? - Sam B
既然你已经定义了一个枚举,为什么不使用带枚举的漂亮 switch case,而不是这个神奇的数字 if? - Or Arbel

56

我刚刚完成了将我的一个应用更新并发送到商店,这个版本向下兼容iOS 5.0,因此我保留了shouldAutorotateToInterfaceOrientation:方法,并添加了下面列出的新方法。

我必须做以下事情:

iOS 6中的自动旋转方式已经改变。在iOS 6中,UIViewController的shouldAutorotateToInterfaceOrientation:方法已被弃用。取而代之的是,您应该使用supportedInterfaceOrientationsForWindow:shouldAutorotate方法。 因此,我添加了这些新方法(并保留了旧方法以实现iOS 5兼容性):

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAllButUpsideDown;    
}
  • 使用视图控制器的viewWillLayoutSubviews方法,并使用视图的边框矩形调整布局。
  • 模态视图控制器:
    willRotateToInterfaceOrientation:duration:
    willAnimateRotationToInterfaceOrientation:duration:
    didRotateFromInterfaceOrientation:方法不再在任何全屏显示自己的视图控制器上调用,例如presentViewController:animated:completion:
  • 然后我修复了需要自动布局的视图。
  • 将启动视图和用于iTunes Store的视图从模拟器复制到PhotoShop中,并将它们导出为png文件。
  • 默认图片的名称是:Default-568h@2x.png,大小为640×1136。如果您的应用程序仅允许iPhone处于横向方向,则还可以提供类似大小的横向模式(状态栏已移除)640×1096。如果您的应用程序只允许横向方向,则也可以在纵向模式下提供类似大小。
  • 我已经放弃了对iOS 4的向后兼容性。这样做的主要原因是因为支持armv6代码已被删除。因此,现在我能够支持的所有设备(运行armv7)都可以升级到iOS 5。
  • 我还生成了支持iPhone 5的armv7s代码,因此无法使用任何第三方框架(如Admob等)直到它们得到更新。

这就是全部内容,但请记住要在iOS 5和iOS 6中测试自动旋转,因为旋转方式发生了变化。


2
我的应用程序已经有了可调整大小的视图,但仍然以信封箱方式启动。即使我将视图的宽度更改为568,它仍然以信封箱方式启动(并且被挤压了)!当我添加了一个Default-568h@2x.png时,它以正确的纵横比启动了。 - Tim R.
如果您想支持iOS 5自动旋转和iOS 6自动旋转,您是否需要在同一文件中包含新方法以及旧的自动旋转方法? - johnbakers
2
andrewx,是的。您支持旧方法(保留以前的方法)并在上面添加新方法。然后,在运行iOS 5时会调用旧方法,而iOS 6会调用新方法。 - Sverrisson
大家好!我已经添加了两种自动旋转的方法,但是没有自动旋转发生。当我倾斜设备时,屏幕仍然保持竖屏状态...这里有什么问题吗? - Bogdan
您在目标 -> 概要页面选择了旋转功能吗? - Sverrisson
显示剩余3条评论

26

不行。

if ([[UIScreen mainScreen] bounds].size.height > 960)

在 iPhone 5 上是错误的。

if ([[UIScreen mainScreen] bounds].size.height == 568)

2
为什么是568?请解释一下。谢谢。 - Christian Pappenberger
6
iPhone 5的屏幕分辨率为1136x640,但所有尺寸都以2个像素为单位以保持与原始iPhone屏幕的一致性 - 苹果公司在iPhone 4中每个方向上将像素数量加倍,但希望所有软件都能无需修改即可运行。因此,568是新屏幕的高度(= 1136/2)。 - Bryan
谢谢,我已经在我的代码中进行了更改。 - endy
1
我喜欢这种方法,因为它只需要一行代码,并且“硬编码”的568与苹果的设备特定启动图像命名约定相匹配。例如 Default-568h@2x.pngApple Docs: App Launch (Default) Images - John Erck

17
@interface UIDevice (Screen)
typedef enum
{
    iPhone          = 1 << 1,
    iPhoneRetina    = 1 << 2,
    iPhone5         = 1 << 3,
    iPad            = 1 << 4,
    iPadRetina      = 1 << 5

} DeviceType;

+ (DeviceType)deviceType;
@end

.m

#import "UIDevice+Screen.h"
@implementation UIDevice (Screen)

+ (DeviceType)deviceType
{
    DeviceType thisDevice = 0;
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
    {
        thisDevice |= iPhone;
        if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
        {
            thisDevice |= iPhoneRetina;
            if ([[UIScreen mainScreen] bounds].size.height == 568)
                thisDevice |= iPhone5;
        }
    }
    else
    {
        thisDevice |= iPad;
        if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
            thisDevice |= iPadRetina;
    }
    return thisDevice;
}

@end

这样,如果你想检测设备是 iPhone 还是 iPad(不考虑屏幕大小),你只需使用:

if ([UIDevice deviceType] & iPhone) 
或者
if ([UIDevice deviceType] & iPad)

如果你只想检测iPhone 5,可以使用:

if ([UIDevice deviceType] & iPhone5)

与Malcom的答案相反,您需要检查才能确定它是否是iPhone,

if ([UIDevice currentResolution] == UIDevice_iPhoneHiRes || 
    [UIDevice currentResolution] == UIDevice_iPhoneStandardRes || 
    [UIDevice currentResolution] == UIDevice_iPhoneTallerHiRes)`

两种方法都没有明显的优劣之分,只是个人偏好而已。


这对我完全没用,也许我漏了什么,但是如果([UIDevice deviceType] & iPhone5)在任何设备上都返回true,无论屏幕大小如何? - Steven Elliott
抱歉,我已经做出了更改。 - endy
如果是Retina iPod,它将返回iPhoneRetina。如果是高iPod,它将返回iPhone5。如果是低分辨率的iPhone,它将返回iPhone。 - endy

5
@Pascal对OP的问题的评论是正确的。仅需添加图像即可去除黑色边框,应用程序将使用整个高度。
您需要通过确定设备正在使用更大的显示器来调整任何CGRects。即,如果您需要将某些内容对齐到屏幕底部。
我确信有一个内置的方法,但我还没有看到任何东西,而且很多内容仍然在NDA之下,因此我们在我们的应用程序中使用的方法非常简单的全局函数。将以下内容添加到.pch文件中,然后它就是一个简单的if( is4InchRetina() ) { ... } 调用来调整您的CGRects等。
static BOOL is4InchRetina()
{
    if (![UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 548 || [UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 568)
        return YES;

    return NO;
}

未经测试,但在iPhone具有双倍大小状态栏的情况下可能存在错误。例如,在通话时。 - endy

3

我认为你可以使用[UIScreen mainScreen].bounds.size.height 并计算对象的步长。在计算步长时,您可以针对两种分辨率设置坐标。

或者您可以像上面那样获取高度并使用 if(iphone5) then... else if(iphone4) then... else if(ipad)。类似这样的东西。

如果您使用storyboards,则需要为新的iPhone创建新的故事板。


1
这很有道理,但正如我上面所说,你不认为苹果会创造出更容易的东西吗? - jturolla
2
嗯,我不知道。这与iPhone和iPhone Retina不同。这个屏幕在高度上有更多的像素,所以比例不同。在主题演讲中展示了(如果我没记错的话),旧应用程序会居中,并在上下方有黑色条带。 - Tomasz Szulc
"@JúlioTurollaRibeiro 你认为苹果会创造出更简单的东西" 这是一个主观问题。如果没有相关信息,没有人能够回答这个问题。因此,这样问并不具有建设性。 - WendiKidd
我想他们通过引入新的相对布局系统使得某些东西更容易了,但是如果你想支持iOS6以下的版本就没用了。不过这个解决方案对我来说很好。谢谢@tomasz - Steven Elliott

3
由于高度中有更多像素,使用坐标的 GCRectMake 等事物不会在版本之间无缝工作,就像我们获得 Retina 时发生的那样。Retina 显示屏上确实可以正常工作,只是 CoreGraphics 坐标系统中的 1 个单位将对应于 2 个物理像素,但您不需要做任何事情,逻辑保持不变。(你曾试过在视网膜 iPhone 上运行非视网膜应用程序吗?)针对实际问题:这就是为什么你不应该使用明确的 CGRectMakes 等方法的原因... 这就是为什么你有像 [[UIScreen mainScreen] applicationFrame] 这样的东西。

2
是的,罗伯特!嗯,像这样的事情到现在为止都有效... - jturolla
@JúlioTurollaRibeiro 更容易?你的意思是苹果将创建一些带有水晶球的工具,来改变充满魔法常数的代码,这些代码仅仅因为巧合而有效(即至今仍然具有相同的屏幕尺寸)吗? - zrzka
2
CGRectMake(0, 0, 320, 480); 在视网膜屏幕上的效果与非视网膜屏幕上相同。 - user529758
也许吧! :) 例如具有表视图的应用程序可以轻松拉伸它。他们可以创建条件拉伸,任何东西!我相信他们在制作出色的编程工具和优秀产品方面做得很好。 - jturolla
@RobertVojta 我知道这个问题 :) 但我想澄清他的误解。当然,上面的代码将在iPhone 5更高的屏幕上出现问题。(我知道它更高 - 我一直在现场直播;-) - user529758
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接