Meine iOS-App verwendet eine benutzerdefinierte Höhe für die UINavigationBar
, die auf dem neuen iPhone X zu Problemen führt.
Weiß jemand bereits, wie er zuverlässig programmgesteuert (in Objective-C) _ erkennt, ob eine App auf dem iPhone X ausgeführt wird?
EDIT:
Natürlich ist es möglich, die Größe des Bildschirms zu überprüfen. Ich frage mich jedoch, ob es eine "eingebaute" Methode wie TARGET_OS_IPHONE
gibt, um iOS zu erkennen ...
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812)
NSLog(@"iPhone X");
}
EDIT 2:
Ich denke nicht, dass meine Frage ein Duplikat der verknüpften Frage ist. Natürlich gibt es Methoden, um verschiedene Eigenschaften des aktuellen Geräts zu "messen" und anhand der Ergebnisse zu entscheiden, welches Gerät verwendet wird. Dies war jedoch nicht der eigentliche Punkt meiner Frage, wie ich in meinem ersten Schnitt betont habe.
Die eigentliche Frage ist: "Ist es möglich, direkt festzustellen, ob das aktuelle Gerät ein iPhone X ist (z. B. durch eine SDK-Funktion) oder muss ich indirekte Messungen verwenden??
Bei den bisherigen Antworten gehe ich davon aus, dass die Antwort lautet: "Nein, es gibt keine direkten Methoden. Messungen sind der Weg".
Basierend auf Ihrer Frage lautet die Antwort nein. Es gibt keine direkten Methoden. Weitere Informationen erhalten Sie hier:
und
Die Höhe des iPhone X beträgt 2436 px
Von Gerätegrößen und Auflösungen :
Von Gerätegrößen und -ausrichtungen :
Swift 3 und höher:
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")
}
}
Ziel 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:
printf("iPhone XS Max");
break;
case 1792:
printf("iPhone XR");
break;
default:
printf("Unknown");
break;
}
}
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");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1334) {
Console.WriteLine("iPhone 6/6S/7/8");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1920 || (UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2208) {
Console.WriteLine("iPhone 6+/6S+/7+/8+");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2436) {
Console.WriteLine("iPhone X, XS");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2688) {
Console.WriteLine("iPhone XS Max");
} else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1792) {
Console.WriteLine("iPhone XR");
} else {
Console.WriteLine("Unknown");
}
}
Basierend auf Ihrer Frage wie folgt:
Oder verwenden Sie screenSize.height
als Float 812.0f
nicht 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");
}
Weitere Informationen finden Sie in den iOS-Richtlinien zur Benutzeroberfläche auf der folgenden Seite:
Swift:
Mit topNotch
ermitteln:
var hasTopNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
Ziel c:
- (BOOL)hasTopNotch {
if (@available(iOS 11.0, *)) {
return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
}
return NO;
}
UPDATE:
Verwenden Sie nicht die userInterfaceIdiom
-Eigenschaft, um den Gerätetyp zu identifizieren, da die Dokumentation für userInterfaceIdiom Folgendes erklärt:
Für universelle Anwendungen können Sie diese Eigenschaft verwenden, um das Verhalten Ihrer Anwendung für einen bestimmten Gerätetyp anzupassen. Beispielsweise haben iPhone- und iPad-Geräte unterschiedliche Bildschirmgrößen. Daher möchten Sie möglicherweise unterschiedliche Ansichten und Steuerelemente basierend auf dem Typ des aktuellen Geräts erstellen.
Das heißt, diese Eigenschaft wird nur verwendet, um den Ansichtsstil der laufenden App zu identifizieren. Die iPhone-App (nicht die Universal-App) kann jedoch über den App Store auf dem iPad installiert werden. In diesem Fall gibt die userInterfaceIdiom
auch die UIUserInterfaceIdiomPhone
zurück.
Der richtige Weg ist, den Rechnernamen über uname
zu erhalten. Überprüfen Sie Folgendes für Details:
Eine andere Möglichkeit, die auf iOS 11 und iOS 12 funktioniert, weil das iPhone X das einzige ist, das oben eine Kerbe hat und ein Inset von 44 aufweist.
Ziel c:
BOOL iPhoneX = NO;
if (@available(iOS 11.0, *)) {
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
if (mainWindow.safeAreaInsets.top > 24.0) {
iPhoneX = YES;
}
}
Swift 4:
/// Has safe area
///
/// with notch: 44.0 on iPhone X, XS, XS Max, XR.
///
/// without notch: 20.0 on iPhone 8 on iOS 12+.
///
static var hasSafeArea: Bool {
guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 24 else {
return false
}
return true
}
Wenn Sie sich im Querformat befinden, müssen Sie möglicherweise den linken und den rechten Bereich des sicheren Bereichs überprüfen.
Edit: _window ist das UIWindow von AppDelegate, wo diese Überprüfung in der Anwendung didFinishLaunchingWithOptions durchgeführt wird.
Antwort für iOS 12 aktualisiert, um zu prüfen, ob top> 24 statt top> 0 ist.
Bearbeiten: Im Simulator können Sie zur Hardware-Statusleiste wechseln. Dadurch wird angezeigt, dass sich die Höhe der Statusleiste auf dem iPhone X unter iOS 11 oder iPhone XS iOS 12 nicht ändert, wenn ein Anruf eingeht. Alles, was sich ändert, ist das Zeitsymbol, das in beiden Fällen einen grünen Hintergrund hat. Hier ist ein Schnappschuss:
Sie müssen je nach Bedarf unterschiedliche Erkennungen des iPhone X durchführen.
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: 24.0 on iPad Pro 12.9" 3rd generation, 20.0 on iPhone 8 on iOS 12+.
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 24
}
return false
}
class var hasBottomSafeAreaInsets: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
// with home indicator: 34.0 on iPhone X, XS, XS Max, XR.
// with home indicator: 20.0 on iPad Pro 12.9" 3rd generation.
return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
class var isIphoneXOrBigger: Bool {
// 812.0 on iPhone X, XS.
// 896.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height >= 812
}
Hinweis: Mischen Sie es eventuell mit UIDevice.current.userInterfaceIdiom == .phone
.
Hinweis: Diese Methode erfordert ein LaunchScreen-Storyboard oder entsprechende LaunchImages
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
}
Hinweis: Diese Methode erfordert ein LaunchScreen-Storyboard oder entsprechende LaunchImages
Rufen Sie die Maschinen-ID ab und vergleichen Sie sie mit dokumentierten Werten:
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"
}
So fügen Sie den Simulator als gültiges iPhone X in Ihre Analyse ein:
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"
}
Um iPhone XS, XS Max und XR einzubeziehen, suchen Sie einfach nach Modellen, die mit "iPhone11" beginnen:
return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")
import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
if #available(iOS 11.0, *) {
return LAContext().biometryType == .typeFaceID
}
return false
}
Auf diese Weise können Sie das iPhone X -Gerät anhand der Abmessungen ermitteln.
Swift
if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
//iPhone X
}
Ziel c
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436) {
//iPhone X
}
Aber,
Dies reicht nicht aus. Was ist, wenn Apple das nächste iPhone mit der gleichen Dimension von iPhone X ankündigt?.
Für neuere Geräte ist der Hardware-String wie folgt.
iPhone 8 - iPhone10,1 oder iPhone 10,4
iPhone 8 Plus - iPhone10,2 oder iPhone 10,5
iPhone X - iPhone10,3 oder iPhone10,6
Check out das Gerätemodell/den Maschinennamen , NICHT die Punkt-/Pixelanzahl direkt in Ihrem Code verwenden, es ist hard code und für die Gerätehardware ohne Bedeutung.
#import <sys/utsname.h>
NSString* deviceName()
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}
Ergebnis:
@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)
Siehe diese Antwort .
Vollständige Code-Implementierung:
#import <sys/utsname.h>
NSString * GetDeviceModel(void)
{
static dispatch_once_t onceToken;
static NSString *strModelID = nil;
dispatch_once(&onceToken, ^{
#if TARGET_IPHONE_SIMULATOR
strModelID = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
#else
struct utsname systemInfo;
uname(&systemInfo);
strModelID = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
#endif
});
return strModelID;
}
// See the `Hardware strings` in https://en.wikipedia.org/wiki/List_of_iOS_devices
BOOL IsiPhoneX(void)
{
NSString *strModelID = GetDeviceModel();
return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"];
}
BOOL IsNotchiPhone(void)
{
NSString *strModelID = GetDeviceModel();
return [strModelID isEqualToString:@"iPhone10,3"] || [strModelID isEqualToString:@"iPhone10,6"] || // iPhone X
[strModelID isEqualToString:@"iPhone11,2"] || [strModelID isEqualToString:@"iPhone11,4"] || [strModelID isEqualToString:@"iPhone11,6"] || // iPhone XS (Max)
[strModelID isEqualToString:@"iPhone11,8"]; // iPhone XR
}
#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_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"]
Hinweis: - Seien Sie vorsichtig, es funktioniert nur für die Ausrichtung im Hochformat
Nachdem ich mir alle Antworten angesehen hatte, tat ich es am Ende:
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
}
}
if UIDevice.isIphoneX {
// is iPhoneX
} else {
// is not iPhoneX
}
Pre Swift 4.1 können Sie überprüfen, ob die App auf einem Simulator ausgeführt wird:
TARGET_OS_SIMULATOR != 0
Ab Swift 4.1 können Sie mit der Bedingung Target-Umgebungsplattform prüfen, ob die App auf einem Simulator ausgeführt wird :
#if targetEnvironment(simulator)
return true
#else
return false
#endif
(Die ältere Methode wird immer noch funktionieren, aber diese neue Methode ist zukunftssicherer)
Alle diese auf Dimensionen basierenden Antworten sind anfällig für fehlerhaftes Verhalten auf zukünftigen Geräten. Sie funktionieren heute, aber was ist, wenn nächstes Jahr ein iPhone mit der gleichen Größe vorhanden ist, die Kamera usw. jedoch unter der Glasscheibe ist, so dass es keine "Kerbe" gibt? Wenn Sie nur die App aktualisieren möchten, ist dies eine schlechte Lösung für Sie und Ihre Kunden.
Sie können auch die Hardware-Modellzeichenfolge wie "iPhone10,1" überprüfen. Dies ist jedoch problematisch, da Apple manchmal unterschiedliche Modellnummern für verschiedene Netzbetreiber auf der ganzen Welt veröffentlicht.
Der richtige Ansatz besteht darin, das obere Layout neu zu gestalten oder die Probleme, die Sie mit der benutzerdefinierten Höhe der Navigationsleiste haben, zu lösen (darauf würde ich mich konzentrieren). Aber wenn Sie sich entscheiden, eines dieser Dinge nicht zu tun, müssen Sie erkennen, dass alles, was Sie tun, ein Hack ist, damit dies funktioniertheute, und Sie müssen es irgendwann korrigieren. Vielleicht mehrmals, um die Hacks am Laufen zu halten.
Swift 4+ Answer
iPhone X, XR, XS, XSMAX:
Hinweis: Echtes Gerät zum Testen
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
}
}
Ja, es ist möglich. Laden Sie die UIDevice-Hardware-Erweiterung herunter (oder installieren Sie sie über CocoaPod 'UIDevice-Hardware') und verwenden Sie
NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];
Beachten Sie, dass dies im Simulator nicht funktioniert, sondern nur auf dem tatsächlichen Gerät.
Ich weiß, dass es nur eine Swift-Lösung ist, aber es könnte jemandem helfen.
Ich habe globals.Swift
in jedem Projekt und eines der Dinge, die ich immer hinzufüge, ist DeviceType
, um das Gerät des Benutzers leicht zu erkennen:
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
static let iPhoneXRMax = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 896.0
static var hasNotch: Bool {
return iPhoneX || iPhoneXRMax
}
}
Dann verwenden Sie es:
if DeviceType.hasNotch {
print("This executes on all phones with a notch")
}
if DeviceType.iPhone678 {
print("This executes on iPhones 6, 7 and 8")
}
Wenn Sie LaunchImage
in Ihrem Projekt verwenden, stellen Sie sicher, dass Sie Bilder für alle unterstützten Geräte (wie XS Max, XR) hinzufügen, da UIScreen.main.bounds
ohne diese keinen richtigen Wert zurückgibt.
Swift 4 wiederverwendbar Erweiterung
public extension UIDevice {
public enum `Type` {
case iPad
case iPhone_unknown
case iPhone_5_5S_5C
case iPhone_6_6S_7_8
case iPhone_6_6S_7_8_PLUS
case iPhone_X_Xs
case iPhone_Xs_Max
case iPhone_Xr
}
public var hasHomeButton: Bool {
switch type {
case .iPhone_X_Xs, .iPhone_Xr, .iPhone_Xs_Max:
return false
default:
return true
}
}
public var type: Type {
if userInterfaceIdiom == .phone {
switch UIScreen.main.nativeBounds.height {
case 1136:
return .iPhone_5_5S_5C
case 1334:
return .iPhone_6_6S_7_8
case 1920, 2208:
return .iPhone_6_6S_7_8_PLUS
case 2436:
return .iPhone_X_Xs
case 2688:
return .iPhone_Xs_Max
case 1792:
return .iPhone_Xr
default:
return .iPhone_unknown
}
}
return .iPad
}
}
Laut der Antwort von @saswanb ist dies eine Swift 4-Version:
var iphoneX = false
if #available(iOS 11.0, *) {
if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
iphoneX = true
}
}
Alle Antworten, die die Variable height
verwenden, sind aus einem Grund nur die Hälfte der Geschichte. Wenn Sie dies überprüfen, wenn die Geräteorientierung landscapeLeft
oder landscapeRight
ist, schlägt die Prüfung fehl, da die height
mit der width
ausgelagert ist.
Deshalb sieht meine Lösung in Swift 4.0 so aus:
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
}
}
Sie sollten nicht davon ausgehen, dass das einzige Gerät, das Apple mit einer anderen UINavigationBar-Höhe freigibt, das iPhone X ist. Versuchen Sie, dieses Problem mit einer allgemeineren Lösung zu lösen. Wenn der Balken immer um 20 Pixel größer sein soll als die Standardhöhe, sollte der Code der Balkenhöhe um 20 Pixel erhöht werden, anstatt ihn auf 64 Pixel (44 Pixel + 20 Pixel) einzustellen.
Swift 3 + 4:
ohne dass ein Pixelwert für die Gerätegröße erforderlich ist
//UIApplication+SafeArea.Swift
extension UIApplication {
static var isDeviceWithSafeArea:Bool {
if #available(iOS 11.0, *) {
if let topPadding = shared.keyWindow?.safeAreaInsets.bottom,
topPadding > 0 {
return true
}
}
return false
}
}
Beispiel:
if UIApplication.isDeviceWithSafeArea {
//e.g. change the frame size height of your UITabBar
}
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
}
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
Normalerweise benötigt der Programmierer ihn, um ihn nach oben oder unten zu beschränken, damit diese Methoden helfen können
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
}
Für vor dem iPhone X geben diese Methoden Folgendes zurück: 0
Für iPhone X: 44 und 34 entsprechend
Dann fügen Sie diese Extras einfach zu den oberen oder unteren Randbedingungen hinzu
Für diejenigen, die 2001px statt 2436px für die native Begrenzungshöhe erhalten (wie ich), liegt dies daran, dass Sie Ihre App mit einem älteren SDK vor iOS 11 (Xcode 8 statt Xcode 9) erstellt haben. Mit einem älteren SDK zeigt iOS die Apps "black boxed" auf dem iPhone X an, anstatt den Bildschirm Edge-to-Edge über die oberste "Sensorkerbe" hinaus zu erweitern. Dadurch wird die Bildschirmgröße reduziert, weshalb diese Eigenschaft 2001 statt 2436 zurückgegeben wird.
Die einfachste Lösung besteht darin, nur für beide Größen zu prüfen, ob Sie nur an der Geräteerkennung interessiert sind. Ich habe diese Methode zum Erkennen von FaceID verwendet, während mit einem älteren Xcode SDK erstellt wurde, in dem der ENUM-Wert nicht den biometrischen Typ angibt. In dieser Situation schien die Geräteerkennung anhand der Bildschirmhöhe der beste Weg zu sein, um zu wissen, ob das Gerät FaceID vs. TouchID hatte, ohne Xcode aktualisieren zu müssen.
- (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;
}
}
Ich habe auf Ihre Antworten zu den Antworten von else eingegangen und die Erweiterung von Swift auf UIDevice vorgenommen. Ich mag Swift Enums und "alles in Ordnung" & atomisiert. Ich habe eine Lösung entwickelt, die sowohl auf dem Gerät als auch im Simulator funktioniert.
Vorteile: - einfache Schnittstelle, Verwendung z. Mit UIDevice.current.isIPhoneX
- UIDeviceModelType
enum können Sie modellspezifische Funktionen und Konstanten, die Sie in Ihrer App verwenden möchten, problemlos erweitern, z. Eckenradius
Nachteil: - Es handelt sich um eine modellspezifische Lösung, nicht um eine Auflösung, z. Wenn Apple ein anderes Modell mit denselben Spezifikationen produziert, funktioniert dies nicht richtig und Sie müssen ein anderes Modell hinzufügen, damit dies funktioniert => Sie müssen Ihre App aktualisieren.
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
}
}
Verwenden Sie KEINE Bildschirmpixelgröße, da andere Lösungen vorgeschlagen haben. Dies ist schlecht, da dies zu falschen Ergebnissen für zukünftige Geräte führen kann. funktioniert nicht, wenn UIWindow noch nicht gerendert ist (AppDelegate), funktioniert nicht in Querformat-Apps und kann im Simulator fehlschlagen, wenn die Skalierung festgelegt ist.
Ich habe stattdessen ein Makro für diesen Zweck erstellt. Es ist sehr einfach zu verwenden und setzt Hardware-Flags ein, um die oben genannten Probleme zu vermeiden.
Bearbeiten: Aktualisiert zur Unterstützung von iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max
if (IS_DEVICE_IPHONEX) {
//do stuff
}
Ja, wirklich.
Kopieren Sie dies einfach an einer beliebigen Stelle, ich bevorzuge das Ende meiner .h-Datei nach @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]);\
})()\
)
Ich stütze mich auf die Höhe der Statusleiste, um herauszufinden, ob es sich um ein iPhone X handelt:
if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
// It is an iPhone X
}
Dies ist für die Anwendung un Portrait. Sie können die Größe auch entsprechend der Ausrichtung des Geräts überprüfen. Auf anderen iPhones ist die Statusleiste möglicherweise ausgeblendet, sodass die Bildhöhe 0
ist. Auf dem iPhone X wird die Statusleiste nie ausgeblendet.
Ich benutzte Peter Kreinz 'Code (weil es sauber war und tat, was ich brauchte), aber dann wurde mir klar, dass es funktioniert, wenn sich das Gerät im Porträt befindet (da die obere Polsterung offensichtlich oben ist) .__ Eine Erweiterung erstellt, die alle Ausrichtungen mit den entsprechenden Auffüllungen berücksichtigt, ohne die Bildschirmgröße zu ändern:
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
}
}
Und auf Ihrer Anrufseite können Sie einfach:
let res = UIDevice.current.isIphoneX
Alternativ können Sie ' DeviceKit ' pod ..__ auschecken. Nach der Installation müssen Sie lediglich das Gerät überprüfen:
import DeviceKit
let device = Device()
if device == .iPhoneX {
// place your code here
}
Ich musste das gleiche Problem kürzlich lösen. Und obwohl diese Frage definitiv beantwortet ist ("Nein"), kann dies anderen helfen, die ein spezifisches Layout für das iPhone X benötigen.
Ich war nicht wirklich daran interessiert, ob das Gerät ein iPhone X war. Ich interessierte mich dafür, ob das Gerät ein gekerbtes Display hatte.
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
}
Sie könnten auch eine Variable hasOnScreenHomeIndicator
nach denselben Zeilen schreiben (überprüfen Sie jedoch den unteren sicheren Bereich, vielleicht?).
Im obigen Abschnitt wird meine Erweiterung auf UIView
verwendet, um unter iOS 10 und früheren Versionen bequem auf die sicheren Bereiche zuzugreifen.
@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
}
}
}
Es gibt mehrere Gründe, um wissen zu wollen, was das Gerät ist.
Sie können die Höhe und Breite des Geräts überprüfen. Dies ist nützlich für das Layout, aber normalerweise möchten Sie dies nicht, wenn Sie das genaue Gerät kennen möchten.
Zu Layoutzwecken können Sie auch UIView.safeAreaInsets
verwenden.
Wenn Sie den Gerätenamen anzeigen möchten, um ihn z. B. zu Diagnosezwecken in eine E-Mail aufzunehmen, nachdem Sie das Gerätemodell mithilfe von sysctl ()
abgerufen haben, können Sie das Äquivalent dazu verwenden, um den Namen anzugeben:
$ curl http://appledevicenames.com/devices/iPhone10,6
iPhone X
Ich denke, Apple möchte nicht, dass wir manuell prüfen, ob das Gerät "Notch" oder "Home Indicator" hat aber der Code, der funktioniert, ist:
-(BOOL)hasTopNotch{
if (@available(iOS 11.0, *)) {
float max_safe_area_inset = MAX(MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right),MAX([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom, [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left));
return max_safe_area_inset >= 44.0;
}
return NO;
}
-(BOOL)hasHomeIndicator{
if (@available(iOS 11.0, *)) {
int iNumberSafeInsetsEqualZero = 0;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top == 0.0)iNumberSafeInsetsEqualZero++;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.right == 0.0)iNumberSafeInsetsEqualZero++;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.bottom == 0.0)iNumberSafeInsetsEqualZero++;
if([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.left == 0.0)iNumberSafeInsetsEqualZero++;
return iNumberSafeInsetsEqualZero <= 2;
}
return NO;
}
Einige der anderen Beiträge funktionieren nicht. Zum Beispiel hat das iPhone 6S mit "In-Call-Statusleiste" (grüne Leiste) im Hochformatmodus einen großen sicheren oberen Bereich. Mit meinem Code werden alle Fälle aufgenommen ( auch wenn das Gerät im Hoch- oder Querformat startet )
Der beste und einfachste Weg, um herauszufinden, ob das Gerät ein iPhone X ist,
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)))}
Und die Kennung ist entweder "iPhone10,3" oder "iPhone10,6" für iPhone X.
Nur in Portrait verwende ich die Breite und Höhe des Rahmens der Ansicht, um Folgendes zu überprüfen:
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")
}
}
Die Abmessungen des Hochformatbildschirms sind hier aufgeführt
Mit der Veröffentlichung von iOS 12 können Geräte wie das iPhone X in diese Kategorie fallen.
`
extension UIDevice {
var isPortrait: Bool {
return UIDeviceOrientationIsPortrait(orientation) ||
UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation)
}
var isDeviceWith_XShape : Bool {
if self.userInterfaceIdiom == .phone {
if isPortrait
{
switch UIScreen.main.nativeBounds.height {
case 2436,2688,1792:
print("iPhone X, Xs, Xr, Xs Max")
return true
default:
print("Any other device")
return false
}
}
else
{
switch UIScreen.main.nativeBounds.width {
case 2436,2688,1792:
print("iPhone X, Xs, Xr, Xs Max")
return true
default:
print("Any other device")
return false
}
}
}
else
{
return false
}
}`
Für eine schnelle Lösung gefällt mir Folgendes:
let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>
Erkennen eines der Geräte mithilfe einfacher Methoden. Wie unten,
func isPhoneDevice() -> Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}
func isDeviceIPad() -> Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
func isPadProDevice() -> Bool {
let SCREEN_WIDTH: CGFloat = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT: CGFloat = UIScreen.main.bounds.size.height
let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)
return UIDevice.current.userInterfaceIdiom == .pad && SCREEN_MAX_LENGTH == 1366.0
}
func isPhoneXandXSDevice() -> Bool {
let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)
return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 812.0
}
func isPhoneXSMaxandXRDevice() -> Bool {
let SCREEN_WIDTH = CGFloat(UIScreen.main.bounds.size.width)
let SCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.size.height)
let SCREEN_MAX_LENGTH: CGFloat = fmax(SCREEN_WIDTH, SCREEN_HEIGHT)
return UIDevice.current.userInterfaceIdiom == .phone && SCREEN_MAX_LENGTH == 896.0
}
und rufen Sie so an,
if isPhoneDevice() {
// Your code
}