【问题标题】:How to specify size for iPhone 6/7 customised edge-to-edge image?如何为 iPhone 6/7 自定义边到边图像指定尺寸?
【发布时间】:2014-11-11 14:04:24
【问题描述】:

假设我希望一个捆绑图像占据 iPhone 应用程序中所有可用的屏幕宽度 - 例如横幅。我会为宽度为1242pxiPhone 6 plus 创建宽度为320pxmy_banner.png、宽度为640pxmy_banner@2x.pngmy_banner@3x.png。但是iPhone 6 的分辨率是750×1334 像素。它仍然与具有640px 宽度的iPhone 4 和5 共享@2x 后缀。

有什么推荐的方式好的方式来指定针对iPhone 6750px宽度优化的图像文件?似乎不能在asset catalog 中完成?应该以编程方式完成吗? iPhone 6还有其他的后缀可以用吗?

(图片摘自http://www.iphoneresolution.com

【问题讨论】:

  • 苹果不是说i6+图像是@3x吗?
  • iPhone 5 和 iPhone 6 的屏幕比例相同。您应该为 iPhone 6 分辨率准备 2x 图像,并且它将为 iPhone 5 毫无问题地进行下采样。
  • @CraigOtis 您可以在资产目录中创建多个图像,并在检查屏幕边界后使用它们。但在我看来,这将是不必要的矫枉过正。
  • @Desdenova 同意。我希望(对于 OP)会有一些类似的奖金前缀,就像 Apple 推出 iPhone 5 时一样。类似:background@2x.pngbackground-750w@2x.png
  • @Jonny 但这不是一回事。我对不同设备的分辨率(或 PPI)并不感到困惑。我认为让您失望的是该表中的 渲染像素物理像素。我不喜欢 1.171875 上采样,并希望通过使用针对设备的实际屏幕分辨率优化的图像来避免它。 iPhone 6 是750x1334。如果您知道 iPhone 6 无法在此分辨率下显示图像资源,那么这将是新信息,并且可以很好地回答这个问题。但我认为情况并非如此。

标签: ios objective-c iphone cocoa-touch iphone-6


【解决方案1】:

在我看来,很多这些答案都想解决如何限制 imageView,我认为您关心的是加载正确的媒体文件?我会想出自己的未来可扩展解决方案,如下所示:

“UIImage+DeviceSpecificMedia.h” - (UIImage 上的一个类别)

界面:

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, thisDeviceClass) {

    thisDeviceClass_iPhone,
    thisDeviceClass_iPhoneRetina,
    thisDeviceClass_iPhone5,
    thisDeviceClass_iPhone6,
    thisDeviceClass_iPhone6plus,

    // we can add new devices when we become aware of them

    thisDeviceClass_iPad,
    thisDeviceClass_iPadRetina,


    thisDeviceClass_unknown
};

thisDeviceClass currentDeviceClass();

@interface UIImage (DeviceSpecificMedia)

+ (instancetype )imageForDeviceWithName:(NSString *)fileName;

@end

实施:

#import "UIImage+DeviceSpecificMedia.h"

thisDeviceClass currentDeviceClass() {

    CGFloat greaterPixelDimension = (CGFloat) fmaxf(((float)[[UIScreen mainScreen]bounds].size.height),
                                                    ((float)[[UIScreen mainScreen]bounds].size.width));

    switch ((NSInteger)greaterPixelDimension) {
        case 480:
            return (( [[UIScreen mainScreen]scale] > 1.0) ? thisDeviceClass_iPhoneRetina : thisDeviceClass_iPhone );
            break;
        case 568:
            return thisDeviceClass_iPhone5;
            break;
        case 667:
            return thisDeviceClass_iPhone6;
            break;
        case 736:
            return thisDeviceClass_iPhone6plus;
            break;
        case 1024:
            return (( [[UIScreen mainScreen]scale] > 1.0) ? thisDeviceClass_iPadRetina : thisDeviceClass_iPad );
            break;
        default:
            return thisDeviceClass_unknown;
            break;
    }
}

@implementation UIImage (deviceSpecificMedia)

+ (NSString *)magicSuffixForDevice
{
    switch (currentDeviceClass()) {
        case thisDeviceClass_iPhone:
            return @"";
            break;
        case thisDeviceClass_iPhoneRetina:
            return @"@2x";
            break;
        case thisDeviceClass_iPhone5:
            return @"-568h@2x";
            break;
        case thisDeviceClass_iPhone6:
            return @"-667h@2x"; //or some other arbitrary string..
            break;
        case thisDeviceClass_iPhone6plus:
            return @"-736h@3x";
            break;

        case thisDeviceClass_iPad:
            return @"~ipad";
            break;
        case thisDeviceClass_iPadRetina:
            return @"~ipad@2x";
            break;

        case thisDeviceClass_unknown:
        default:
            return @"";
            break;
    }
}

+ (instancetype )imageForDeviceWithName:(NSString *)fileName
{
    UIImage *result = nil;
    NSString *nameWithSuffix = [fileName stringByAppendingString:[UIImage magicSuffixForDevice]];

    result = [UIImage imageNamed:nameWithSuffix];
    if (!result) {
        result = [UIImage imageNamed:fileName];
    }
    return result;
}

@end

【讨论】:

  • 没错!似乎目前没有更好的方法可以做到这一点。这是一种以编程方式进行的好方法。
  • 你成功了!谢谢!
  • 谢谢 :) 关于此示例需要注意的一点是,我已经公开了 thisDeviceClass 枚举和 c 函数以在 .h 文件中获取它,可能是假设会有其他用途/需要它。有些人可能更喜欢将这些东西隐藏在 .m 文件中,需要知道,封装等。很高兴为您服务。我可以有赏金吗? :D
  • 如果我用 iPhone6 大小设置标签栏的背景图像大小并使用上面的代码加载图像,我仍然无法使用上面的代码设置图像标签栏图片的背景图片名称为footer_iPhone4New-667@2x,尺寸为750*110,但静态图片设置不正确,需要帮助。
  • 对不起,我认为这超出了这个问题/答案的范围,听起来您正在获取您期望的文件。也许 UITabBar 不准备处理该大小的图像,或者它可能有错误。我建议您提出一个新问题并链接回此页面作为您尝试过的内容。祝你好运 :) ps 快速建议,您的尺寸 {750, 110} 是否是两个尺寸的条形尺寸的两倍(以考虑比例)...?我怀疑您可能需要调整您为此栏包含的图像的尺寸.. ;)
【解决方案2】:

我正在使用以下技巧,因为有些东西确实有效:

  • 特定设备的资产目录
  • 在 320x640 的基础上为 1x2x 指定图像
  • 在 320x568 (iPhone 5) 的基础上为 4 2x3x 指定图像
  • 专门为 iPhone 6 创建一个新的图像集(因为这是唯一在边到边绑定方面出现问题的设备)
  • 仅为 iPhone 6 提供全分辨率 (750x1334) 的 2x 图片

声明一个常量

#define IS_IPHONE_6 [[UIScreen mainScreen]nativeBounds].size.width == 750.0 ? true : false

并像这样使用它:

UIImage *image = [UIImage imageNamed:@"Default_Image_Name"];
if(IS_IPHONE_^) {
    image = [UIImage imageNamed:@"Iphone6_Image_Name"];
}

这可能不是最漂亮的解决方案,但它可以工作,至少只要苹果不为边缘到边缘绑定提供更好的 API。

【讨论】:

    【解决方案3】:

    自动布局应该有助于解决这种情况..

    现在告诉我@Nicklas Berglund 如果设备旋转你会怎么做?假设您现在处于横向模式。您将如何填充不再包含在图像资源中的水平空间?

    只是思想的食物。自动布局应该照顾您的屏幕,无论您在哪个方向或在哪个设备上运行您的应用程序..

    也许 Apple 应该在未来开始在图像资源中定位设备方向?

    让我们回到您的问题。解决方案是将您的 @2x 图像替换为 750 像素宽的图像,然后让自动布局完成其工作。哦,是的,这是棘手的部分..

    如果你只是添加约束来适应它,它会在 4" 屏幕上显示时水平挤压它,但你可以使用乘数来适当地缩放图像。这是你可以做到的:

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageFooterView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imageFooterView)]];
    
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[imageFooterView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imageFooterView)]];
    
    
    float aspectRatio = imageFooterView.frame.size.height/imageFooterView.frame.size.width;
    
    [imageFooterView addConstraint:[NSLayoutConstraint constraintWithItem:imageFooterView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:imageFooterView attribute:NSLayoutAttributeWidth multiplier:aspectRatio constant:0.0f]];
    

    【讨论】:

    • 这可以使用情节提要吗?
    【解决方案4】:

    我也找不到解决方法,因为我的背景图片与除 iPhone 6 之外的所有设备上的资产目录完美匹配。我的修复(我在 SpriteKit 中完成了此操作)?

    if (bgNode.size.width != self.frame.size.width) {
            bgNode.texture = [SKTexture textureWithImageNamed:@"i6bg.png"];
            [bgNode runAction:[SKAction scaleXTo:self.frame.size.width/bgNode.size.width y:self.frame.size.width/bgNode.size.height duration:.1]];
        }
    

    bgNode 是设备拉起的背景图片。如果是 iPhone 6,它将不适合屏幕,因此背景图像宽度不会与屏幕宽度相同。当设备被识别为 iPhone 6 时,我将纹理更改为 R4 纹理(视网膜的@2x)并将其缩放到正确的尺寸。

    我尝试对常规的@2x 图像做同样的事情,但缩放后的图像看起来很糟糕(它被拉得太长并且很明显)。随着 R4 纹理的缩放,宽度/高度的比例稍微好一些,因此变化甚至不明显。我希望这能让您了解在 Apple 添加 iPhone 6 资产之前您可以做什么。

    【讨论】:

    • 谢谢。有各种解决方法。我可能会使用 UIScreen 检查宽度:[UIScreen mainScreen] bounds].size.width 并将其包装在一个函数中以检查它是否在 iPhone 6 上运行。很难相信 Apple 还没有为此创建一个漂亮的解决方案,例如 iPhone 6 资产.
    • 没错。我想知道我的资产图像是否有问题,因为我拥有的 iPhone 6 背景图像不适合整个屏幕。我在搜索谷歌时发现了您发布的另一篇文章,并意识到我需要应用一种解决方法。我打算把check方式改成[UIScreen mainScreen]...,谢谢指教!
    【解决方案5】:

    希望这将解决您与自定义边到边图像相关的所有问题。
    Xcode 6 - xcassets for universal image support

    确保如果您使用的是自动布局,则所有边缘的检查引脚都设置为零,并且未选中对边距的约束。

    您还可以访问此链接以获取启动屏幕图像:
    http://www.paintcodeapp.com/news/iphone-6-screens-demystified
    http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions

    【讨论】:

      【解决方案6】:

      我向苹果技术支持提出了同样的问题,他们确认对于全屏图像无法在资产目录中完成:“目前,资产目录无法加载特定于设备的图像。如果您的应用需要要支持特定于设备的图像,您需要实现自己的代码来检测屏幕尺寸并选择合适的图像。您可以使用以下链接提交增强请求。请务必解释此功能的使用案例。“

      【讨论】:

        【解决方案7】:

        我检查了通过 Xcode 6 和 iPhone 6+ 的横向版本从资产目录生成的启动图像的命名约定,例如:LaunchImage-Landscape-736h@3x.png

        基于此,我假设对于视网膜设备,假设基础文件 desert.png:

        • desert@2x:iPhone 4s (320 x 420)
        • desert-568h@2x:iPhone 5、5C 和 5S (320 x 568)
        • desert-667h@2x:iPhone 6 (375 x 667)
        • desert-736h@3x:iPhone 6+ (414 x 736)
        • desert@2x~ipad:iPad (1024 x 768)

        【讨论】:

        • 但是-667h@2x 后缀并没有什么神奇之处,还是有?如果有图片my_image-667h@2x.png 指定图片my-image.png 时不会自动使用它对吗?
        • 你不应该指定.png部分让SDK选择正确的图像。
        • 我很马虎。不过我很确定-667h@2x 后缀没有什么神奇之处。
        • @NiklasBerglund 我在这里做了一些魔术 :) stackoverflow.com/a/26612635/2790648
        • 这似乎行不通......你是否能够让它工作,或者这个命名约定纯粹是猜测?
        【解决方案8】:

        这种情况下没有原生资产支持,所以我认为最好手动完成,因为将来使用未记录的文件名可能会很容易中断。

        【讨论】:

          【解决方案9】:

          只需测量设备尺寸并调用您想要的图像。即以编程方式进行

          所以在你的 appdelegate 中有全局变量

          deviceHeight = self.window.frame.size.height;
          deviceWidth = self.window.frame.size.width;
          

          您可以反复调用。 然后检查它们并调用适当的图像

          if (deviceWidth == 640){
          image = IPHONE4IMAGE;
          deviceString = @"iPhone4";
          }
          else...
          

          【讨论】:

            【解决方案10】:

            就我而言,我有兴趣让我的基本视图控制器子类具有与我的启动图像相同的背景图像。

            注意:除非这是您的特定要求,否则此方法将不起作用。

            此外,即使我尝试为 iPhone 6 (750x1334) 创建正确尺寸的背景图像,将该图像作为图案图像加载到视图的背景颜色中,最终还是以不合需要的方式放大了图像.

            This answer 给了我需要的代码,以便为我找到一个好的解决方案。

            这是我为使启动图像与UIViewController 的背景图像匹配的代码(反之亦然):

            - (void)viewDidLoad {
                [super viewDidLoad];
                UIImage *background         = [UIImage imageNamed:[self splashImageName]];
                UIColor *backgroundColor    = [UIColor colorWithPatternImage:background];
                self.view.backgroundColor   = backgroundColor;
            }
            - (NSString *)splashImageName {
                UIInterfaceOrientation orientation  = [[UIApplication sharedApplication] statusBarOrientation];
                CGSize viewSize                     = self.view.bounds.size;
                NSString *viewOrientation           = @"Portrait";
                if (UIDeviceOrientationIsLandscape(orientation)) {
                    viewSize                        = CGSizeMake(viewSize.height, viewSize.width);
                    viewOrientation                 = @"Landscape";
                }
                NSArray *imagesDict                 = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
                for (NSDictionary *dict in imagesDict) {
                    CGSize imageSize                = CGSizeFromString(dict[@"UILaunchImageSize"]);
                    if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]])
                        return dict[@"UILaunchImageName"];
                }
                return nil;
            }
            

            【讨论】:

              【解决方案11】:

              请尝试使用此类以编程方式更改图像名称。

              import UIKit
              
              class AGTools: NSObject {
                  class func fullWidthImage(imageName: String!) -> String!{
                      let screenWidth = UIScreen.mainScreen().bounds.size.width
                      switch (screenWidth){
                      case 320:
                          // scale 2x or 1x
                          return (UIScreen.mainScreen().scale > 1.0) ? "\(imageName)@2x" : imageName
                      case 375:
                          return "\(imageName)-375w@2x"
                      case 414:
                          return "\(imageName)-414w@3x"
                      default:
                          return imageName
                      }
                  }
              }
              

              像这样使用这个方法。

              _imgTest.image = UIImage(named: AGTools.fullWidthImage("imageName"))
              

              【讨论】:

                【解决方案12】:

                首先,您需要将 imageView 配置为覆盖整个屏幕,Autolayout 对这项工作有很大帮助,请查看下面的链接和了解如何固定约束(前导空格、尾随空格、顶部空格和底部空格)使用情节提要

                http://www.thinkandbuild.it/learn-to-love-auto-layout/

                第二步是在您的图片资源(下图)上创建设备特定的图片集,以根据设备显示不同的图片。

                查看此信息图: http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions

                它解释了旧 iPhone、iPhone 6 和 iPhone 6 Plus 之间的区别。您可以查看以点、渲染像素和物理像素为单位的屏幕尺寸比较

                就是这样

                如果您有任何问题,请提供反馈。

                【讨论】:

                • 谢谢,但问题与布局约束无关。这是关于不同设备之间的像素比率。 Apple 没有提供方便的方法(类似于@2x、@3x)来指定为 iPhone 6 优化的图像。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-05-08
                • 2011-12-23
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多