302 votes

Comment détecter l'iPhone 5 (appareils à écran large) ?

Je viens de passer à Xcode 4.5 GM et j'ai découvert que vous pouvez désormais appliquer la taille "4" Retina" à votre contrôleur de vue dans le storyboard.

Maintenant, si je veux créer une application qui fonctionne à la fois sur l'iPhone 4 et 5, je dois bien sûr construire chaque fenêtre deux fois, mais je dois aussi détecter si l'utilisateur a un iPhone avec un écran de 3,5" ou 4" et ensuite appliquer la vue.

Comment dois-je m'y prendre ?

2 votes

Il n'est pas nécessaire de construire chaque "fenêtre" deux fois. Seules celles qui sont censées correspondre exactement à la taille de l'écran devront être relayées. La solution semble plutôt évidente, il suffit de vérifier les dimensions de la fenêtre et d'ajouter une décision de cas basée sur la taille renvoyée.

1 votes

En gros, c'est vrai, mais je veux utiliser la taille supplémentaire de l'écran d'une manière complètement différente, comme on pourrait le faire avec un écran paysage.

0 votes

Vérifiez cette URL : stackoverflow.com/questions/4779221/

467voto

Macmade Points 27414

Tout d'abord, vous ne devez pas reconstruire toutes vos vues pour les adapter à un nouvel écran, ni utiliser des vues différentes pour des tailles d'écran différentes.

Utilisez le redimensionnement automatique d'iOS, de sorte que vos vues peuvent s'ajuster et s'adapter à toute taille d'écran.

Ce n'est pas très difficile, lisez quelques documents à ce sujet. Cela vous fera gagner beaucoup de temps.

iOS 6 offre également de nouvelles fonctionnalités à ce sujet.
Veillez à lire le Changements dans l'API d'iOS 6 sur le site Web des développeurs d'Apple.
Et vérifiez le nouvel iOS 6 AutoLayout capacités.

Cela dit, si vous avez vraiment besoin de détecter l'iPhone 5, vous pouvez simplement vous fier à l'outil de détection de l'iPhone. la taille de l'écran .

[ [ UIScreen mainScreen ] bounds ].size.height

L'écran de l'iPhone 5 a une hauteur de 568.
Vous pouvez imaginer une macro, pour simplifier tout cela :

#define IS_IPHONE_5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )

L'utilisation de fabs avec l'epsilon est ici pour éviter les erreurs de précision, lors de la comparaison de points flottants, comme indiqué dans les commentaires par H2CO3.

Donc, à partir de maintenant, vous pouvez l'utiliser dans les instructions if/else standard :

if( IS_IPHONE_5 )
{}
else
{}

Edit - Meilleure détection

Comme l'ont dit certaines personnes, cela ne fait que détecter un écran large et non un vrai iPhone 5.

Les prochaines versions de l'iPod touch disposeront peut-être aussi d'un tel écran, nous pourrons donc utiliser un autre jeu de macros.

Renommons la macro originale IS_WIDESCREEN :

#define IS_WIDESCREEN ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )

Et ajoutons des macros de détection de modèles :

#define IS_IPHONE ( [ [ [ UIDevice currentDevice ] model ] isEqualToString: @"iPhone" ] )
#define IS_IPOD   ( [ [ [ UIDevice currentDevice ] model ] isEqualToString: @"iPod touch" ] )

De cette façon, nous pouvons nous assurer que nous avons un modèle d'iPhone ET un écran large, et nous pouvons redéfinir l'élément IS_IPHONE_5 macro :

#define IS_IPHONE_5 ( IS_IPHONE && IS_WIDESCREEN )

Notez également que, comme indiqué par @LearnCocos2D, ces macros ne fonctionneront pas si l'application n'est pas optimisée pour l'écran de l'iPhone 5 (absence de l'image Default-568h@2x.png), car la taille de l'écran sera toujours de 320x480 dans ce cas.

Je ne pense pas que cela puisse être un problème, car je ne vois pas pourquoi nous voudrions détecter un iPhone 5 dans une application non optimisée.

IMPORTANT - Prise en charge d'iOS 8

Sous iOS 8, le bounds de l UIScreen reflète maintenant le orientation du dispositif .
Il est donc évident que le code précédent ne fonctionnera pas tout de suite.

Afin de résoudre ce problème, vous pouvez simplement utiliser la nouvelle fonction nativeBounds au lieu de bounds Il ne change pas avec l'orientation, et il est basé sur un mode portrait.
Notez que les dimensions de nativeBounds est mesurée en pixels, donc pour un iPhone 5, la hauteur sera de 1136 au lieu de 568.

Si vous visez également iOS 7 ou une version inférieure, assurez-vous d'utiliser la détection des fonctions, comme l'appellent les utilisateurs. nativeBounds antérieures à iOS 8 feront planter votre application :

if( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] )
{
    /* Detect using nativeBounds - iOS 8 and greater */
}
else
{
    /* Detect using bounds - iOS 7 and lower */
}

Vous pouvez adapter les macros précédentes de la manière suivante :

#define IS_WIDESCREEN_IOS7 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
#define IS_WIDESCREEN_IOS8 ( fabs( ( double )[ [ UIScreen mainScreen ] nativeBounds ].size.height - ( double )1136 ) < DBL_EPSILON )
#define IS_WIDESCREEN      ( ( [ [ UIScreen mainScreen ] respondsToSelector: @selector( nativeBounds ) ] ) ? IS_WIDESCREEN_IOS8 : IS_WIDESCREEN_IOS7 )

Et évidemment, si vous devez détecter un iPhone 6 ou 6 Plus, utilisez les tailles d'écran correspondantes.

7 votes

C'est faux, vous devrez utiliser #define IS_IPHONE_5 ( [ [ UIScreen mainScreen ] bounds ].size.height == 568 )

0 votes

Oups, c'est ma faute... Merci pour le commentaire : )

1 votes

Comparaison de nombres à virgule flottante se échouer. Pourquoi ne pas vérifier height > 500 à la place ?

232voto

hfossli Points 6815

Testé et conçu pour toute combinaison de SDK et d'OS :

Swift

Ajout de types d'iPad. L'iPad 2 et l'iPad mini sont des iPads non-retina. Alors que l'iPad Mini 2 et plus, l'iPad 3, 4, l'iPad Air, Air 2, Air 3, et l'iPad Pro 9.7 ont la même résolution logique de 1024. L'iPad Pro a une résolution maximale de 1366. Référence

import UIKit

public enum DisplayType {
    case unknown
    case iphone4
    case iphone5
    case iphone6
    case iphone6plus
    case iPadNonRetina
    case iPad
    case iPadProBig
    static let iphone7 = iphone6
    static let iphone7plus = iphone6plus
}

public final class Display {
    class var width:CGFloat { return UIScreen.main.bounds.size.width }
    class var height:CGFloat { return UIScreen.main.bounds.size.height }
    class var maxLength:CGFloat { return max(width, height) }
    class var minLength:CGFloat { return min(width, height) }
    class var zoomed:Bool { return UIScreen.main.nativeScale >= UIScreen.main.scale }
    class var retina:Bool { return UIScreen.main.scale >= 2.0 }
    class var phone:Bool { return UIDevice.current.userInterfaceIdiom == .phone }
    class var pad:Bool { return UIDevice.current.userInterfaceIdiom == .pad }
    class var carplay:Bool { return UIDevice.current.userInterfaceIdiom == .carPlay }
    class var tv:Bool { return UIDevice.current.userInterfaceIdiom == .tv }
    class var typeIsLike:DisplayType {
        if phone && maxLength < 568 {
            return .iphone4
        }
        else if phone && maxLength == 568 {
                return .iphone5
        }
        else if phone && maxLength == 667 {
            return .iphone6
        }
        else if phone && maxLength == 736 {
            return .iphone6plus
        }
        else if pad && !retina {
            return .iPadNonRetina
        }
        else if pad && retina && maxLength == 1024 {
            return .iPad
        }
        else if pad && maxLength == 1366 {
            return .iPadProBig
        }
        return .unknown
    }
}

Voyez-le en action https://gist.github.com/hfossli/bc93d924649de881ee2882457f14e346

Note : Si par exemple l'iPhone 6 est en mode zoomé, l'interface utilisateur est une version zoomée de l'iPhone 5. Ces fonctions ne déterminent pas le type d'appareil, mais le mode d'affichage. Ainsi, l'iPhone 5 est le résultat souhaité dans cet exemple.

Objectif-C

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0)

#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT))
#define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT))
#define IS_ZOOMED (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

#define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0)
#define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0)
#define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

Utilisation : http://pastie.org/9687735

Note : Si par exemple l'iPhone 6 est en mode zoomé, l'interface utilisateur est une version zoomée de l'iPhone 5. Ces fonctions ne déterminent pas le type d'appareil, mais le mode d'affichage. Ainsi, l'iPhone 5 est le résultat souhaité dans cet exemple.

1 votes

L'iPhone 5 présentera une taille d'écran normale de 480x320, sans la nouvelle image par défaut. Pour moi, c'est un comportement souhaité.

3 votes

Un ajout qui pourrait être utile est #define IS_RETINA ([[UIScreen mainScreen] scale] == 2.0) qui aidera à déterminer la différence entre l'iPhone4 et l'iPhone5 et l'iPad Retina et non-retina.

0 votes

Un ajout qui pourrait être utile est #define IS_WIDESCREEN ([[UIScreen mainScreen] bounds].size.height == 568) et ensuite : #define IS_IPHONE_5 (IS_IPHONE && IS_WIDESCREEN)

69voto

Samrat Mazumdar Points 777

Une solution très simple

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    CGSize result = [[UIScreen mainScreen] bounds].size;
    if(result.height == 480)
    {
        // iPhone Classic
    }
    if(result.height == 568)
    {
        // iPhone 5
    }
}

1 votes

Haha court et simple, j'ai fait la même chose :) bravo pour avoir gardé des frais généraux bas ! mettre des choses dans une macro n'est pas un défi....

2 votes

Eh bien, ne pas mettre les choses dans des macros ou des fonctions a tendance à ne pas être DRY... A partir du moment où vous devez faire cette vérification plus d'une fois...

0 votes

Oui, mais définir une macro comme indiqué ci-dessus, est plus pratique et plus facile, vous n'avez pas besoin de coller ce si... à chaque fois.

28voto

Sam Budda Points 3446

Nous devons maintenant tenir compte des tailles d'écran de l'iPhone 6 et 6Plus. Voici une réponse mise à jour

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    //its iPhone. Find out which one?

    CGSize result = [[UIScreen mainScreen] bounds].size;
    if(result.height == 480)
    {
        // iPhone Classic
    }
    else if(result.height == 568)
    {
        // iPhone 5
    }
    else if(result.height == 667)
    {
        // iPhone 6
    }
   else if(result.height == 736)
    {
        // iPhone 6 Plus
    }
}
else
{
     //its iPad
}

Quelques informations utiles

iPhone 6 Plus   736x414 points  2208x1242 pixels    3x scale    1920x1080 physical pixels   401 physical ppi    5.5"
iPhone 6        667x375 points  1334x750 pixels     2x scale    1334x750 physical pixels    326 physical ppi    4.7"
iPhone 5        568x320 points  1136x640 pixels     2x scale    1136x640 physical pixels    326 physical ppi    4.0"
iPhone 4        480x320 points  960x640 pixels      2x scale    960x640 physical pixels     326 physical ppi    3.5"
iPhone 3GS      480x320 points  480x320 pixels      1x scale    480x320 physical pixels     163 physical ppi    3.5"

0 votes

C'est juste que ça ne marche pas pour moi iPhone 5 a décidé comme 4 iPhone 6+ n'a pas décidé du tout Oh j'ai compris je suis en paysage je devrais changer la hauteur avec la largeur :)

0 votes

Si votre application est en mode paysage, assurez-vous de remplacer result.height par result.width.

0 votes

Hmm sur l'iPhone 4 (iOS 6.0) il n'y a pas eu d'échange :( cela peut être un problème d'iOS 6.0 ou un iPhone 4 ?

15voto

LearnCocos2D Points 43044

J'ai pris la liberté de mettre la macro de Macmade dans une fonction C, et de la nommer correctement car elle détecte disponibilité de l'écran large y PAS nécessairement l'iPhone 5.

La macro ne détecte pas non plus l'exécution sur un iPhone 5 dans le cas où le projet ne comprend pas l'option Default-568h@2x.png . Sans la nouvelle image par défaut, l'iPhone 5 affichera une taille d'écran normale de 480x320 (en points). La vérification ne porte donc pas uniquement sur la disponibilité d'un écran large, mais aussi sur les points suivants le mode écran large est activé également.

BOOL isWidescreenEnabled()
{
    return (BOOL)(fabs((double)[UIScreen mainScreen].bounds.size.height - 
                                               (double)568) < DBL_EPSILON);
}

0 votes

Je préfère toujours les macros, pour des raisons de performance. Veuillez voir la modification de ma réponse. Il vérifie également le modèle.

1 votes

Vous avez également raison de dire qu'un iPhone 5 rapportera une taille d'écran normale de 480x320, sans la nouvelle image par défaut. Mais je pense qu'il est inutile de détecter un iPhone 5 dans une application non optimisée : )

0 votes

@Macmade En effet, il n'y a aucun intérêt, mais c'est bon à garder en tête au cas où la détection ne fonctionne pas. De plus, les fonctions peuvent être inline d. Ils seront également intégrés là où l'optimiseur du compilateur pense que c'est une bonne idée et où il peut savoir que c'est permis (par exemple, la fonction est dans le même module). L'implémentation de ce genre de choses à travers une fonction peut parfois apporter une vérification de type supplémentaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X