web-dev-qa-db-fra.com

Comment spécifier la taille d'une image bord à bord personnalisée pour iPhone 6/7?

Supposons que je souhaite qu'une image fournie occupe toute la largeur d'écran disponible dans une application iPhone, par exemple une bannière. Je créerais my_banner.png avec largeur 320px, [email protected] avec largeur 640px et [email protected] pour iPhone 6 plus avec largeur 1242px. Mais la résolution de iPhone 6 est 750×1334 pixels. Il partage toujours le @2x suffixe avec les iPhone 4 et 5 qui ont 640px largeur.

Quelle est la manière recommandée ou une bonne manière de spécifier un fichier image a été optimisé pour le 750px largeur de iPhone 6? On dirait que cela ne peut pas être fait dans un asset catalog? Cela devrait-il être fait par programme? Existe-t-il un autre suffixe pouvant être utilisé pour iPhone 6?

iPhone 4,5,6 screen sizes (Image extraite de http://www.iphoneresolution.com )

60
Niklas Berglund

Il me semble que beaucoup de ces réponses veulent savoir comment limiter l'imageView, où je pense que vous êtes préoccupé par le chargement du bon fichier multimédia? Je proposerais ma propre solution extensible future, quelque chose comme ceci:

"UIImage + DeviceSpecificMedia.h" - (une catégorie sur UIImage)

Interface:

#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

La mise en oeuvre:

#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
43
Jef

J'utilise le truc suivant car certaines choses fonctionnent réellement:

  • Catalogue d'actifs pour des périphériques spécifiques
  • Spécifiez les images pour 1x, 2x sur la base de 320x640
  • Spécifiez les images pour 4 2x et 3x sur la base de 320x568 (iPhone 5)
  • Créez spécifiquement un nouveau jeu d'images pour l'iPhone 6 (il s'agit du seul périphérique qui pose problème avec les liaisons Edge à Edge)
  • Ne fournissez que 2x image pour iPhone 6 en pleine résolution (750x1334)

Déclarer une constante

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

et l'utiliser comme ça:

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

ce n'est peut-être pas la plus belle solution, mais cela fonctionne, du moins tant que Apple ne fournit pas une meilleure API pour les liaisons Edge to Edge.

4

Auto Layout est censé aider à résoudre ce problème.

Maintenant, dites-moi @ Nicklas Berglund, que feriez-vous si l'appareil tournait? Disons que vous êtes maintenant en mode paysage. Comment voulez-vous remplir l'espace horizontal qui n'est plus dans les ressources d'image?

Juste de quoi nourrir vos idées .. La mise en page automatique est censée prendre soin de votre écran, quelle que soit son orientation ou le périphérique sur lequel vous exécutez votre application ..

Peut-être que Apple devrait commencer à cibler les orientations des périphériques dans les ressources d'image à l'avenir?

Revenons à votre question. La solution consiste à remplacer vos images @ 2x par des images de 750 pixels de large, puis de laisser la disposition automatique faire son travail. Oh oui, c'est la partie la plus délicate ..

Si vous ajoutez simplement des contraintes pour l’ajuster, il sera comprimé horizontalement lorsqu’il sera affiché à l’écran de 4 ", mais vous pouvez utiliser des multiplicateurs pour redimensionner l’image de manière appropriée. Voici comment procéder:

[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]];
2
Bms270

J'ai posé la même question au support technique de Apple) et ils ont confirmé que cela ne pouvait pas être fait pour une image plein écran dans le catalogue des ressources: "Actuellement, le catalogue des ressources ne dispose d'aucun moyen de charger des périphériques spécifiques. Si votre application doit prendre en charge des images spécifiques à un appareil, vous devez implémenter votre propre code pour détecter la taille de l'écran et choisir l'image appropriée. Vous pouvez déposer une demande d'amélioration en utilisant le lien suivant. Assurez-vous d'expliquer votre cas d'utilisation cette fonctionnalité. "

1
Qiulang

Je ne pouvais pas trouver un moyen de le faire non plus, car j'avais une image d'arrière-plan parfaitement dimensionnée avec le catalogue des ressources sur tous les appareils, à l'exception de l'iPhone 6. Mon correctif (je l'ai fait dans 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 est l'image d'arrière-plan qui est extraite par le périphérique. S'il s'agit d'un iPhone 6, il ne s'adaptera pas à l'écran et la largeur de l'image d'arrière-plan ne sera donc pas identique à celle de l'écran. Lorsque l'appareil est reconnu en tant qu'iPhone 6, je modifie la texture en la texture R4 (le @ 2x pour la rétine) et la redimensionne aux dimensions correctes.

J'ai essayé de faire la même chose avec l'image @ 2x normale, mais l'image redimensionnée était très mauvaise (elle était trop étendue et trop visible). Avec la texture R4 mise à l'échelle, les proportions largeur/hauteur sont un peu meilleures et le changement n'est même pas perceptible. J'espère que cela vous donne une idée de ce que vous pouvez faire avant Apple ajoute un actif iPhone 6.

1
Andriko13

J'espère que cela résoudra tous vos problèmes liés à l'image personnalisée Edge to Edge.
Xcode 6 - xcassets pour le support d'image universel

Assurez-vous que si vous utilisez la disposition automatique, vérifiez que pin est défini sur zéro pour toutes les arêtes et que les contraintes de marge ne sont pas cochées.

Vous pouvez également visiter ces liens pour les images de l'écran de lancement:
http://www.paintcodeapp.com/news/iphone-6-screens-demystified
http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions

enter image description here

1
Dhaivat Vyas

S'il vous plaît essayez cette classe pour changer le nom de l'image par programme.

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
        }
    }
}

utilisez cette méthode comme ça.

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

Il n'y a pas de support natif Assets pour ce cas, donc je pense qu'il serait préférable de le faire manuellement, car le travail avec des noms de fichiers non documentés risque de se rompre facilement à l'avenir.

0
Rivera

Il suffit de mesurer les dimensions du périphérique et d’appeler l’image de votre choix. c'est à dire le faire par programmation

Donc, dans votre appdelegate avoir globals

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

que vous pouvez appeler à plusieurs reprises. Puis vérifiez-les et appelez l'image appropriée

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

J'ai vérifié la convention de dénomination d'une image de lancement générée à partir d'un catalogue d'actifs via Xcode 6 et la version paysage pour iPhone 6+, par exemple, avait: LaunchImage-Landscape-736h @ 3x. Png

Sur cette base, je supposerais que ce serait comme suit, pour les dispositifs de rétine, en supposant un fichier de base desert. Png:

  • désert @ 2x: iPhone 4s (320 x 420)
  • désert-568h @ 2x: iPhones 5, 5C et 5S (320 x 568)
  • désert-667h @ 2x: iPhone 6 (375 x 667)
  • desert-736h @ 3x: iPhone 6+ (414 x 736)
  • désert @ 2x ~ ipad: iPad (1024 x 768)
0
Benzi

Dans mon cas, je souhaitais que ma sous-classe de contrôleur de vue de base ait la même image d’arrière-plan que mon image de lancement.

REMARQUE: Cette approche ne fonctionnera pas à moins que ce ne soit votre besoin spécifique.

De même, même lorsque j'ai essayé de créer une image d'arrière-plan de la taille appropriée pour l'iPhone 6 (750x1334), le chargement de cette image en tant qu'image de motif dans une couleur d'arrière-plan pour une vue finissait par redimensionner l'image de manière indésirable.

Cette réponse m'a donné le code dont j'avais besoin pour trouver une bonne solution pour moi.

Voici le code sur lequel je travaille pour que mon image de lancement corresponde à l'image d'arrière-plan de mon UIViewController (ou l'inverse):

- (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;
}
0
mbm29414