Détecter si l'appareil est iPhone X
mon application iOS utilise une hauteur personnalisée pour le UINavigationBar
ce qui entraîne des problèmes sur le nouvel iPhone X.
est-ce que quelqu'un sait déjà fiable détecter programmatiquement (en Objectif-C) si une application est en cours d'exécution sur iPhone X?
EDIT:
bien sûr, vérifier la taille de l'écran est possible, cependant, je me demande s'il y a une certaine méthode "build in" comme TARGET_OS_IPHONE
pour détecter iOS...
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812)
NSLog(@"iPhone X");
}
EDIT 2:
je ne pense pas que ma question est un doublon de la question. Bien sûr, il existe des méthodes de "mesurer" des propriétés différentes de l'appareil et utiliser les résultats pour décider quel appareil est utilisé. Cependant, ce n'était pas le point réel de ma question comme j'ai essayé de souligner dans ma première édition.
la vraie question Est: "Est-il possible de détecter directement si l'appareil est un iPhone X (par exemple, par certains SDK) ou dois-je utiliser des mesures indirectes" ?
Par les réponses apportées jusqu'à présent, je suppose que la réponse est "Non, il n'y a pas de méthodes directes. Les mesures sont la voie à suivre".
30 réponses
basé sur votre question, la réponse est non, il n'y a pas de méthodes directes, pour plus d'informations vous pouvez obtenir les informations de here1 et here2 1519150920"
si vous voulez détecter l'iphone X Hauteur utiliser 2436px
tailles D'écran et résolutions de L'appareil
tailles et Orientations de L'écran du dispositif
Swift 3 et plus
if UIDevice().userInterfaceIdiom == .phone {
switch UIScreen.main.nativeBounds.height {
case 1136:
print("iPhone 5 or 5S or 5C")
case 1334:
print("iPhone 6/6S/7/8")
case 1920, 2208:
print("iPhone 6+/6S+/7+/8+")
case 2436:
print("iPhone X, Xs")
case 2688:
print("iPhone Xs Max")
case 1792:
print("iPhone Xr")
default:
print("unknown")
}
}
Objectif C
if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {
switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) {
case 1136:
printf("iPhone 5 or 5S or 5C");
break;
case 1334:
printf("iPhone 6/6S/7/8");
break;
case 1920, 2208:
printf("iPhone 6+/6S+/7+/8+");
break;
case 2436:
printf("iPhone X, Xs");
break;
case 2688:
print("iPhone Xs Max")
case 1792:
print("iPhone Xr")
default:
printf("unknown");
}
}
Xamarin.iOS
if(UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
{
if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1136)
{
Console.WriteLine("iPhone 5 or 5S or 5C");
}
//etc...
}
basé sur votre question comme suit
ou utilisez screenSize.hauteur en tant que flotteur 812.0f
not int 812
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// 812.0 on iPhone X, XS.
// 896.0 on iPhone XS Max, XR.
if (screenSize.height >= 812.0f)
NSLog(@"iPhone X");
}
pour plus d'informations vous pouvez obtenir ici
Swift
ou de détecter avec topNotch
var hasTopNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
Objectif C
-(BOOL)hasTopNotch{
if (@available(iOS 11.0, *)) {
return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
}
return NO;
}
mise à JOUR
N'utilisez pas la propriété userInterfaceIdiom
pour identifier le type d'appareil, comme l'explique la documentation Apple,
Pour des applications universelles, vous pouvez utiliser cette propriété pour adapter le comportement de votre application pour un type d'appareil. Par exemple, les appareils iPhone et iPad ont différentes tailles d'écran, donc vous pourriez vouloir créer différentes vues et contrôles selon le type de l'appareil actuel.
C'est-à-dire que cette propriété est juste utilisée pour identifier le style de vue de l'application en cours d'exécution. Cependant, l'application iPhone (pas l'universelle) pourrait être installé dans l'appareil iPad via App store, dans ce cas, l'utilisateur interfaceidiom retournera L'Uiuser Interfaceidiomphone, aussi.
la bonne façon est d'obtenir le nom de la machine via uname
, cochez ce thread pour plus de détails.
une autre possibilité, qui fonctionne sur iOS 11 et iOS 12 parce que l'iPhone X est le seul avec un cran au sommet et un médaillon de 44. C'est ce que je détecte vraiment ici:
BOOL iPhoneX = NO;
if (@available(iOS 11.0, *)) {
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
if (mainWindow.safeAreaInsets.top > 20.0) {
iPhoneX = YES;
}
}
et bien sûr, vous pourriez avoir besoin de vérifier les inserts de gauche et de droite de la zone de sécurité si vous êtes dans l'orientation du paysage.
Edit: _window est le UIWindow de l'AppDelegate, où cette vérification est effectuée en application didFinishLaunchingWithOptions.
réponse mise à jour pour iOS 12 pour vérifier si top > 20 au lieu de top > 0.
vous pouvez faire comme ceci pour détecter iPhone x appareil selon la dimension.
Swift
if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
//iPhone X
}
Objectif-C
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436) {
//iPhone X
}
mais ,
Ce n'est pas suffisant. Que faire si Apple a annoncé la prochaine iPhone avec la même dimension de iPhone X. Donc la meilleure façon est d'utiliser la chaîne de matériel pour détecter l'appareil.
pour la chaîne de caractères de l'appareil le plus récent est comme ci-dessous.
iPhone 8 - iPhone10,1 ou iPhone 10,4 151950920"
iPhone 8 Plus - iPhone10,2 ou iPhone 10,5 151950920"
iPhone x - iPhone10,3 or iPhone10,6
vous devez effectuer différentes détections de l'iPhone X en fonction du besoin réel.
pour traiter avec l'échelon supérieur (statusbar, navbar), etc.
class var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
// with notch: 44.0 on iPhone X, XS, XS Max, XR.
// without notch: 20.0 on iPhone 8 on iOS 12+.
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
pour le traitement de l'indicateur de maison inférieur (tabbar), etc.
class var hasBottomSafeAreaInsets: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
// with home indicator: 34.0 on iPhone X, XS, XS Max, XR.
return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
pour la taille des fonds, les caractéristiques plein écran, etc.
class var isIphoneXOrBigger: Bool {
// 812.0 on iPhone X, XS.
// 896.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height >= 812
}
Note: éventuellement le mélanger avec UIDevice.current.userInterfaceIdiom == .phone
Note: cette méthode nécessite d'avoir un panneau de rangement de LaunchScreen ou des limages de launch
pour les arrière-plans ratio, défilement, etc.
class var isIphoneXOrLonger: Bool {
// 812.0 / 375.0 on iPhone X, XS.
// 896.0 / 414.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height / UIScreen.main.bounds.width >= 896.0 / 414.0
}
Note: cette méthode nécessite d'avoir un panneau de rangement de L'écran de launch ou des limages de launch
à des fins d'analyse, les statistiques, le suivi, etc.
récupérez l'Identificateur de la machine et comparez-le à des valeurs documentées:
class var isIphoneX: Bool {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
let model = String(cString: machine)
return model == "iPhone10,3" || model == "iPhone10,6"
}
comprend la simulateur de validité de l'iPhone X dans votre analyse:
class var isIphoneX: Bool {
let model: String
if TARGET_OS_SIMULATOR != 0 {
model = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
} else {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
model = String(cString: machine)
}
return model == "iPhone10,3" || model == "iPhone10,6"
}
pour inclure iPhone XS, XS Max et XR, il suffit de rechercher des modèles commençant par " iPhone11,":
return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")
for faceID support
import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
if #available(iOS 11.0, *) {
return LAContext().biometryType == .typeFaceID
}
return false
}
Vérifiez le nom du modèle de périphérique / machine , N'utilisez pas le nombre de points/pixels dans votre code directement, c'est code dur !
#import <sys/utsname.h>
NSString* deviceName()
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}
résultat:
@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)
Consultez cette réponse .
la Pleine mise en œuvre du code:
#import <sys/utsname.h>
BOOL IsiPhoneX(void)
{
static BOOL isiPhoneX = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
#if TARGET_IPHONE_SIMULATOR
NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
#else
struct utsname systemInfo;
uname(&systemInfo);
NSString *model = [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
#endif
isiPhoneX = [model isEqualToString:@"iPhone10,3"] || [model isEqualToString:@"iPhone10,6"];
});
return isiPhoneX;
}
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_4 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 480.0)
#define IS_IPHONE_5 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0)
#define IS_IPHONE_6PLUS (IS_IPHONE && [[UIScreen mainScreen] nativeScale] == 3.0f)
#define IS_IPHONE_6_PLUS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)
define IS_IPHONE_X (IS_IPHONE & & & [[UIScreen mainScreen] bounds].taille.hauteur == 812,0)
#define IS_IPHONE_XS (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0)
#define IS_IPHONE_X_MAX (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 896.0)
#define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0) // 3.0 for iPhone X, 2.0 for others
#define IS_IPAD_DEVICE [(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"]
Note: - attention, il ne fonctionne bien que pour l'orientation portrait
Après avoir examiné toutes les réponses c'est ce que j'ai fait:
Solution (compatible Swift 4.1)
extension UIDevice {
static var isIphoneX: Bool {
var modelIdentifier = ""
if isSimulator {
modelIdentifier = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
} else {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
modelIdentifier = String(cString: machine)
}
return modelIdentifier == "iPhone10,3" || modelIdentifier == "iPhone10,6"
}
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
Utiliser
if UIDevice.isIphoneX {
// is iPhoneX
} else {
// is not iPhoneX
}
Note
Pre Swift 4.1 vous pouvez vérifier si l'application fonctionne sur un simulateur comme ceci:
TARGET_OS_SIMULATOR != 0
à partir de Swift 4.1 vous pouvez vérifier si l'application fonctionne sur un simulateur en utilisant le environnement Cible de la plateforme de la condition :
#if targetEnvironment(simulator)
return true
#else
return false
#endif
(l'ancienne méthode fonctionnera toujours, mais cette nouvelle méthode est plus dans l'avenir)
toutes ces réponses basées sur les dimensions sont susceptibles d'un comportement incorrect sur les dispositifs futurs. Ils fonctionneront aujourd'hui, mais s'il y a un iPhone l'année prochaine qui est de la même taille mais qui a la caméra, etc. sous la vitre pour qu'il n'y ait pas de "pas"?"Si la seule option est de mettre à jour l'application, alors c'est une mauvaise solution pour vous et vos clients.
vous pouvez aussi vérifier la chaîne de caractères du modèle matériel comme "iPhone10, 1", mais c'est problématique parce que parfois Apple publie différents numéros de modèles pour différents transporteurs dans le monde.
l'approche correcte est de redessiner la disposition du haut, ou de résoudre les problèmes que vous avez avec la hauteur de la barre de navigation personnalisée (c'est ce que je me concentrerais sur). Mais, si vous décidez de ne pas faire l'une ou l'autre de ces choses , réalisez que quoi que vous fassiez est un piratage pour faire en sorte que cela fonctionne aujourd'hui , et vous aurez besoin de le corriger à un moment donné, peut-être à plusieurs reprises, pour garder les hacks de travail.
Oui, c'est possible. Télécharger le UIDevice-extension matérielle (ou installer via CocoaPod 'UIDevice-Hardware') et ensuite utiliser:
NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];
noter que cela ne fonctionnera pas dans le simulateur, seulement sur le dispositif réel.
SWIFT 4+ Answer
iPhone X, XR, XS, XSMAX:
Note: Il faut un dispositif réel pour l'essai
let deviceType = UIDevice.current.modelName
switch deviceType {
case "iPhone10,3", "iPhone10,6":
print("iPhoneX")
case "iPhone11,2":
print("iPhone XS")
case "iPhone11,4":
print("iPhone XS Max")
case "iPhone11,6":
print("iPhone XS Max China")
case "iPhone11,8":
print("iPhone XR")
default:
break
}
extension UIDevice {
var modelName: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return identifier
}
}
selon la réponse de @saswanb, c'est une version Swift 4:
var iphoneX = false
if #available(iOS 11.0, *) {
if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
iphoneX = true
}
}
je sais que ce n'est qu'une solution Swift , mais cela pourrait aider quelqu'un.
j'ai globals.swift
dans chaque projet et l'une des choses que j'ai toujours ajouter, c'est DeviceType
de détecter facilement l'appareil de l'utilisateur:
struct ScreenSize {
static let width = UIScreen.main.bounds.size.width
static let height = UIScreen.main.bounds.size.height
static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
static let maxWH = max(ScreenSize.width, ScreenSize.height)
}
struct DeviceType {
static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH < 568.0
static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 568.0
static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 667.0
static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 736.0
static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxWH == 812.0
}
puis l'utiliser:
if DeviceType.iPhoneX {
print("This executes only on iPhoneX")
}
vous ne devez pas supposer que le seul appareil que Apple libère avec une hauteur UINavigationBar différente sera l'iPhone X. essayer de résoudre ce problème en utilisant une solution plus générique. Si vous voulez que la barre soit toujours plus grande de 20px que sa hauteur par défaut, votre code devrait ajouter 20px à la hauteur de la barre, au lieu de la mettre à 64px (44px + 20px).
toutes les réponses qui utilisent le height
ne sont que la moitié de l'histoire pour une raison. Si vous allez vérifier comme cela lorsque l'orientation de l'appareil est landscapeLeft
ou landscapeRight
le contrôle échouera, parce que le height
est remplacé par le width
.
C'est pourquoi ma solution ressemble à ceci dans Swift 4.0:
extension UIScreen {
///
static var isPhoneX: Bool {
let screenSize = UIScreen.main.bounds.size
let width = screenSize.width
let height = screenSize.height
return min(width, height) == 375 && max(width, height) == 812
}
}
struct ScreenSize {
static let width = UIScreen.main.bounds.size.width
static let height = UIScreen.main.bounds.size.height
static let maxLength = max(ScreenSize.width, ScreenSize.height)
static let minLength = min(ScreenSize.width, ScreenSize.height)
static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
}
struct DeviceType {
static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength < 568.0
static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 568.0
static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 667.0
static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 736.0
static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 812.0
static let IS_IPAD = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1024.0
static let IS_IPAD_PRO = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1366.0
}
Swift 3 + 4:
sans besoin de la valeur de pixel de taille de périphérique
//UIApplication+SafeArea.swift
extension UIApplication {
static var isDeviceWithSafeArea:Bool {
if #available(iOS 11.0, *) {
if let topPadding = shared.keyWindow?.safeAreaInsets.top,
topPadding > 0 {
return true
}
}
return false
}
}
exemple:
if UIApplication.isDeviceWithSafeArea {
//e.g. change the frame size height of your UITabBar
}
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
- (BOOL)isIphoneX {
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.keyWindow;
CGFloat topPadding = window.safeAreaInsets.top;
if(topPadding>0) {
return YES;
}
else {
return NO;
}
}
else {
return NO;
}
}
habituellement, le programmeur en a besoin pour forcer vers le haut ou vers le bas, de sorte que ces méthodes peuvent aider
static func extraTop() -> CGFloat {
var top: CGFloat = 0
if #available(iOS 11.0, *) {
if let t = UIApplication.shared.keyWindow?.safeAreaInsets.top {
top = t
}
}
return top
}
static func extraBottom() -> CGFloat {
var bottom: CGFloat = 0
if #available(iOS 11.0, *) {
if let b = UIApplication.shared.keyWindow?.safeAreaInsets.bottom {
bottom = b
}
}
return bottom
}
pour avant iPhone x ces méthodes retourner: 0
pour iPhone X: 44 et 34 en conséquence
alors il suffit d'ajouter ces extras aux contraintes du haut ou du bas
pour ceux qui obtiennent 2001px au lieu de 2436px pour la hauteur native bounds (comme moi), c'est parce que vous avez construit votre application avec un SDK plus ancien, avant iOS 11 (Xcode 8 au lieu de Xcode 9). Avec un SDK plus ancien, iOS affichera les applications " black boxed "sur l'iPhone X au lieu d'étendre l'écran bord à bord, au-delà du haut"sensor notch". Cela réduit la taille de l'écran qui est pourquoi cette propriété retourne 2001 au lieu de 2436.
la solution la plus simple est de vérifier pour les deux tailles si vous êtes seulement intéressé par la détection de périphérique. J'ai utilisé cette méthode pour détecter FaceID tout en construisant avec un vieux SDK Xcode qui n'a pas la valeur ENUM spécifiant le type biométrique. Dans cette situation, la détection de l'appareil à l'aide de la hauteur de l'écran semblait être la meilleure façon de savoir si L'appareil avait un FaceID vs TouchID sans avoir à mettre à jour Xcode.
j'ai élaboré sur votre sur les réponses d'autre et fait l'extension rapide sur UIDevice. J'aime swift enums et "tout est en ordre" et atomisée. J'ai créé la solution qui fonctionne à la fois sur l'appareil et le simulateur.
avantages:
- interface simple, utilisation par exemple UIDevice.current.isIPhoneX
- UIDeviceModelType
enum vous donne la possibilité d'étendre facilement les caractéristiques et les constantes spécifiques au modèle que vous voulez utiliser dans votre application, par exemple cornerRadius
désavantage: - c'est le modèle solution spécifique, pas de résolution spécifique-par exemple, si Apple produit un autre modèle avec les mêmes spécifications, cela ne fonctionnera pas correctement et vous devez ajouter un autre modèle pour que cela fonctionne => vous devez mettre à jour votre application.
extension UIDevice {
enum UIDeviceModelType : Equatable {
///iPhoneX
case iPhoneX
///Other models
case other(model: String)
static func type(from model: String) -> UIDeviceModelType {
switch model {
case "iPhone10,3", "iPhone10,6":
return .iPhoneX
default:
return .other(model: model)
}
}
static func ==(lhs: UIDeviceModelType, rhs: UIDeviceModelType) -> Bool {
switch (lhs, rhs) {
case (.iPhoneX, .iPhoneX):
return true
case (.other(let modelOne), .other(let modelTwo)):
return modelOne == modelTwo
default:
return false
}
}
}
var simulatorModel: String? {
guard TARGET_OS_SIMULATOR != 0 else {
return nil
}
return ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"]
}
var hardwareModel: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let model = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return model
}
var modelType: UIDeviceModelType {
let model = self.simulatorModel ?? self.hardwareModel
return UIDeviceModelType.type(from: model)
}
var isIPhoneX: Bool {
return modelType == .iPhoneX
}
}
je me fie à la hauteur du cadre de la barre D'État pour détecter si c'est un iPhone X:
if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
// It is an iPhone X
}
C'est pour l'application de l'onu portrait. Vous pouvez également vérifier la taille en fonction de l'orientation du périphérique. De plus, sur d'autres iPhones, la barre D'état peut être cachée, de sorte que la hauteur du cadre est 0
. Sur iPhone X, la barre D'État n'est jamais cachée.
j'utilisais le code de Peter Kreinz (parce qu'il était propre et a fait ce dont j'avais besoin) mais ensuite j'ai réalisé qu'il fonctionne Juste quand l'appareil est sur le portrait (depuis rembourrage supérieur sera sur le dessus, évidemment) J'ai donc créé une extension pour gérer toutes les orientations avec ses rembourrages respectifs, sans relayer sur la taille de l'écran:
extension UIDevice {
var isIphoneX: Bool {
if #available(iOS 11.0, *), isIphone {
if isLandscape {
if let leftPadding = UIApplication.shared.keyWindow?.safeAreaInsets.left, leftPadding > 0 {
return true
}
if let rightPadding = UIApplication.shared.keyWindow?.safeAreaInsets.right, rightPadding > 0 {
return true
}
} else {
if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 0 {
return true
}
if let bottomPadding = UIApplication.shared.keyWindow?.safeAreaInsets.bottom, bottomPadding > 0 {
return true
}
}
}
return false
}
var isLandscape: Bool {
return UIDeviceOrientationIsLandscape(orientation) || UIInterfaceOrientationIsLandscape(UIApplication.shared.statusBarOrientation)
}
var isPortrait: Bool {
return UIDeviceOrientationIsPortrait(orientation) || UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)
}
var isIphone: Bool {
return self.userInterfaceIdiom == .phone
}
var isIpad: Bool {
return self.userInterfaceIdiom == .pad
}
}
et sur votre site d'appel vous venez de:
let res = UIDevice.current.isIphoneX
j'ai dû résoudre le même problème récemment. Et alors que cette question est définitivement répondue ("Non"), cela peut aider d'autres qui ont besoin iPhone X comportement de layout spécifique.
Je n'étais pas vraiment intéressé à savoir si l'appareil était iPhone X. j'étais intéressé à savoir si l'appareil avait un affichage entaillé.
private static var hasNotchedDisplay: Bool {
if let window = UIApplication.shared.keyWindow {
return (window.compatibleSafeAreaInsets.top > 20.0 || window.compatibleSafeAreaInsets.left > 0.0 || window.compatibleSafeAreaInsets.right > 0.0)
}
return false
}
vous pouvez aussi écrire une variable hasOnScreenHomeIndicator
dans le même sens (bien que vérifier la zone de sécurité du bas, peut-être?).
ce qui précède utilise mon extension sur UIView
pour un accès pratique à la zone de sécurité insets sur iOS 10 et plus tôt.
@objc public extension UIView {
@objc public var compatibleSafeAreaInsets: UIEdgeInsets {
if #available(iOS 11.0, *) {
return safeAreaInsets
} else {
return .zero
}
}
@objc public var compatibleSafeAreaLayoutGuide: UILayoutGuide {
if #available(iOS 11.0, *) {
return safeAreaLayoutGuide
} else {
return layoutMarginsGuide
}
}
}
alternativement, vous pouvez sortir" DeviceKit " pod. Une fois installé, tout ce que vous devez faire pour vérifier l'appareil est:
import DeviceKit
let device = Device()
if device == .iPhoneX {
// place your code here
}
N'utilisez pas la taille de pixel d'écran comme d'autres solutions l'ont suggéré, c'est mauvais car il peut en résulter de faux positifs pour les dispositifs futurs; ne fonctionnera pas si UIWindow n'a pas encore rendu (AppDelegate), ne fonctionnera pas dans les applications de paysage, et peut échouer sur simulateur si l'échelle est définie.
j'ai, au lieu de cela, fait une macro à cet effet, il est très facile à utiliser et s'appuie sur des indicateurs matériels pour prévenir les problèmes mentionnés ci-dessus.
modifier: mis à jour pour soutenir iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max
À Utiliser:
if (IS_DEVICE_IPHONEX) {
//do stuff
}
Oui, vraiment.
Macro:
il suffit de copier coller ceci n'importe où, je préfère le bas de mon .h du fichier après le @end
#import <sys/utsname.h>
#if TARGET_IPHONE_SIMULATOR
#define IS_SIMULATOR YES
#else
#define IS_SIMULATOR NO
#endif
#define IS_DEVICE_IPHONEX (\
(^BOOL (void){\
NSString *__modelIdentifier;\
if (IS_SIMULATOR) {\
__modelIdentifier = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];\
} else {\
struct utsname __systemInfo;\
uname(&__systemInfo);\
__modelIdentifier = [NSString stringWithCString:__systemInfo.machine encoding:NSUTF8StringEncoding];\
}\
NSString *__iPhoneX_GSM_Identifier = @"iPhone10,6";\
NSString *__iPhoneX_CDMA_Identifier = @"iPhone10,3";\
NSString *__iPhoneXR_Identifier = @"iPhone11,8";\
NSString *__iPhoneXS_Identifier = @"iPhone11,2";\
NSString *__iPhoneXSMax_China_Identifier = @"iPhone11,6";\
NSString *__iPhoneXSMax_Other_Identifier = @"iPhone11,4";\
return ([__modelIdentifier isEqualToString:__iPhoneX_GSM_Identifier] || [__modelIdentifier isEqualToString:__iPhoneX_CDMA_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXR_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXS_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_China_Identifier] || [__modelIdentifier isEqualToString:__iPhoneXSMax_Other_Identifier]);\
})()\
)
Il y a plusieurs raisons de vouloir savoir ce que l'appareil est.
-
vous pouvez vérifier la hauteur (et la largeur) de l'appareil. Ceci est utile pour la mise en page, mais vous ne voulez pas le faire si vous voulez connaître l'exacte appareil.
-
pour la mise en page, vous pouvez également utiliser
UIView.safeAreaInsets
. -
si vous voulez afficher le nom du périphérique, par exemple, pour être inclus dans un email à des fins de diagnostic, après avoir récupéré le modèle de l'appareil en utilisant
sysctl ()
, vous pouvez utiliser l'équivalent de ceci pour représenter le nom:$ curl http://appledevicenames.com/devices/iPhone10,6 iPhone X
pour une correction rapide, j'aime ça:
let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>
la meilleure et la plus facile façon de détecter si l'appareil est iPhone X est,
https://github.com/stephanheilner/UIDevice-DisplayName
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier}
return identifier + String(UnicodeScalar(UInt8(value)))}
et l'identificateur est soit "iPhone10, 3" ou "iPhone10, 6" pour iPhone X.
Dans Portrait uniquement j'utilise le point de vue de l'image de la largeur et de la hauteur de vérifier:
override func viewDidLoad() {
super.viewDidLoad()
// iPhone Xr: -414 x 896
// iPhone Xs Max: -414 x 896
// iPhone X, Xs: -375 x 812
if view.frame.width == 414 && view.frame.height == 896 || view.frame.width == 375 && view.frame.height == 812 {
print("iPhone X")
} else {
print("not iPhone X")
}
}