ios - informacion - iphone x plus
Detecta si el dispositivo es iPhone X (30)
Mi aplicación iOS utiliza una altura personalizada para
UINavigationBar
que genera algunos problemas en el nuevo iPhone X.
¿Alguien sabe cómo detectar de manera confiable mediante programación (en Objective-C) si una aplicación se ejecuta en iPhone X?
EDITAR:
Por supuesto, es posible verificar el tamaño de la pantalla, sin embargo, me pregunto si hay algún método "
TARGET_OS_IPHONE
" como
TARGET_OS_IPHONE
para detectar iOS ...
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812)
NSLog(@"iPhone X");
}
EDITAR 2:
No creo que mi pregunta sea un duplicado de la pregunta vinculada. Por supuesto, hay métodos para "medir" diferentes propiedades del dispositivo actual y usar los resultados para decidir qué dispositivo se usa. Sin embargo, este no era el punto real de mi pregunta, ya que traté de enfatizar en mi primera edición.
La pregunta real es: "¿Es posible detectar directamente si el dispositivo actual es un iPhone X (por ejemplo, mediante alguna función del SDK) o tengo que usar mediciones indirectas" ?
Según las respuestas dadas hasta ahora, supongo que la respuesta es "No, no hay métodos directos. Las medidas son el camino a seguir".
Alternativamente, puede consultar el pod '' DeviceKit ''. Una vez instalado, todo lo que necesita hacer para verificar el dispositivo es:
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
}
Confío en la altura del marco de la barra de estado para detectar si se trata de un iPhone X:
if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
// It is an iPhone X
}
Esto es para aplicación un retrato.
También puede verificar el tamaño de acuerdo con la orientación del dispositivo.
Además, en otros iPhones, la barra de estado puede estar oculta, por lo que la altura del marco es
0
.
En el iPhone X, la barra de estado nunca está oculta.
En Vertical solo uso el ancho y la altura del marco de la vista para verificar:
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")
}
}
Estaba usando el código de Peter Kreinz (porque estaba limpio e hizo lo que necesitaba) pero luego me di cuenta de que funciona justo cuando el dispositivo está en posición vertical (dado que el relleno superior estará en la parte superior, obviamente) Así que creé una extensión para manejar todo orientaciones con sus respectivos rellenos, sin retransmitir en el tamaño de la pantalla:
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
}
}
Y en su sitio de llamadas simplemente:
let res = UIDevice.current.isIphoneX
Expliqué tus respuestas sobre las de los demás e hice una rápida extensión en UIDevice. Me gustan las enumeraciones rápidas y "todo en orden" y atomizado. He creado una solución que funciona tanto en el dispositivo como en el simulador.
Ventajas: - interfaz simple, uso, por ejemplo
UIDevice.current.isIPhoneX
-
UIDeviceModelType
enum le brinda la capacidad de ampliar fácilmente las características y constantes específicas del modelo que desea utilizar en su aplicación, por ejemplo, cornerRadius
Desventaja: es una solución específica del modelo, no una resolución específica, por ejemplo, si Apple producirá otro modelo con las mismas especificaciones, esto no funcionará correctamente y debe agregar otro modelo para que funcione => necesita actualizar su aplicación
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
}
}
Hay varias razones para querer saber qué es el dispositivo.
-
Puede verificar la altura del dispositivo (y el ancho). Esto es útil para el diseño, pero generalmente no desea hacerlo si desea conocer el dispositivo exacto.
-
Para fines de diseño, también puede usar
UIView.safeAreaInsets
. -
Si desea mostrar el nombre del dispositivo, por ejemplo, para incluirlo en un correo electrónico con fines de diagnóstico, después de recuperar el modelo del dispositivo
sysctl ()
, puede usar el equivalente de este para calcular el nombre:$ curl http://appledevicenames.com/devices/iPhone10,6 iPhone X
NO use el tamaño de píxel de la pantalla como lo han sugerido otras soluciones, esto es malo ya que puede dar lugar a falsos positivos para dispositivos futuros; no funcionará si UIWindow aún no se ha procesado (AppDelegate), no funcionará en aplicaciones horizontales y puede fallar en el simulador si se establece la escala.
En cambio, hice una macro para este propósito, es muy fácil de usar y se basa en indicadores de hardware para evitar los problemas antes mencionados.
Editar: actualizado para admitir iPhoneX, iPhone XS, iPhoneXR, iPhoneXS Max
Usar:
if (IS_DEVICE_IPHONEX) {
//do stuff
}
Sí, de verdad.
Macro:
Simplemente copie y pegue esto en cualquier lugar, prefiero la parte inferior de mi archivo .h después
@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]);/
})()/
)
Para aquellos que obtienen 2001px en lugar de 2436px para la altura de los límites nativos (como yo), es porque construiste tu aplicación con un SDK anterior, antes de iOS 11 (Xcode 8 en lugar de Xcode 9). Con un SDK anterior, iOS mostrará las aplicaciones "en caja negra" en el iPhone X en lugar de extender la pantalla de borde a borde, más allá de la "muesca del sensor" superior. Esto reduce el tamaño de la pantalla, por lo que esa propiedad devuelve 2001 en lugar de 2436.
La solución más simple es verificar ambos tamaños si solo está interesado en la detección de dispositivos. Utilicé este método para detectar FaceID mientras construía con un Xcode SDK más antiguo que no tiene el valor ENUM que especifica el tipo biométrico. En esta situación, la detección del dispositivo usando la altura de la pantalla parecía ser la mejor manera de saber si el dispositivo tenía FaceID vs TouchID sin tener que actualizar Xcode.
Para una solución rápida, me gusta esto:
let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>
Tuve que resolver el mismo problema recientemente. Y aunque esta pregunta se responde definitivamente ("No"), esto puede ayudar a otros que necesitan un comportamiento de diseño específico para iPhone X.
No estaba realmente interesado en saber si el dispositivo era iPhone X. Estaba interesado en saber si el dispositivo tenía una pantalla con muescas.
@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
}
}
}
También podría escribir una
hasOnScreenHomeIndicator
variable a lo largo de las mismas líneas (aunque, tal vez, verifique el área segura inferior).
Lo anterior usa mi extensión activada
UIView
para un acceso conveniente a las inserciones de área segura en iOS 10 y versiones anteriores.
import DeviceKit
let device = Device()
if device == .iPhoneX {
// place your code here
}
Deberá realizar diferentes detecciones de iPhone X según la necesidad real.
para tratar con la muesca superior (barra de estado, barra de navegación), 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: 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
}
para tratar con el indicador de inicio inferior (barra de pestañas), 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.
// with home indicator: 20.0 on iPad Pro 12.9" 3rd generation.
return UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
para tamaño de fondos, funciones de pantalla completa, etc.
class var isIphoneXOrBigger: Bool {
// 812.0 on iPhone X, XS.
// 896.0 on iPhone XS Max, XR.
return UIScreen.main.bounds.height >= 812
}
Nota: eventualmente mézclelo con
UIDevice.current.userInterfaceIdiom == .phone
Nota: este método requiere tener un guión gráfico de LaunchScreen o imágenes de lanzamiento adecuadas
para relación de fondos, funciones de desplazamiento, 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
}
Nota: este método requiere tener un guión gráfico de LaunchScreen o imágenes de lanzamiento adecuadas
para análisis, estadísticas, seguimiento, etc.
Obtenga el identificador de la máquina y compárelo con los valores documentados:
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"
}
Para incluir el simulador como un iPhone X válido en sus análisis:
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"
}
Para incluir iPhone XS, XS Max y XR, simplemente busque modelos que comiencen con "iPhone11":
return model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,")
para soporte de faceID
import LocalAuthentication
/// will fail if user denies canEvaluatePolicy(_:error:)
class var canUseFaceID: Bool {
if #available(iOS 11.0, *) {
return LAContext().biometryType == .typeFaceID
}
return false
}
Después de ver todas las respuestas, esto es lo que terminé haciendo:
Solución (compatible con 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
}
}
Utilizar
if UIDevice.isIphoneX {
// is iPhoneX
} else {
// is not iPhoneX
}
Nota
Pre Swift 4.1 puede verificar si la aplicación se ejecuta en un simulador de esta manera:
TARGET_OS_SIMULATOR != 0
A partir de Swift 4.1 y versiones posteriores, puede verificar si la aplicación se está ejecutando en un simulador utilizando la condición de plataforma del entorno Target :
#if targetEnvironment(simulator)
return true
#else
return false
#endif
(el método anterior seguirá funcionando, pero este nuevo método es más a prueba de futuro)
No debe suponer que el único dispositivo que Apple lanzará con una altura diferente de UINavigationBar será el iPhone X. Intente resolver este problema utilizando una solución más genérica. Si desea que la barra siempre sea 20px más grande que su altura predeterminada, su código debe agregar 20px a la altura de la barra, en lugar de establecerla en 64px (44px + 20px).
Otra posibilidad, que funciona en iOS 11 y iOS 12 porque el iPhone X es el único con una muesca en la parte superior y un recuadro de 44. Eso es lo que realmente estoy detectando aquí:
C objetivo:
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
}
Y, por supuesto, es posible que deba verificar las inserciones del área segura izquierda y derecha si está en orientación horizontal.
Editar: _window es la UIWindow de AppDelegate, donde esta comprobación se realiza en la aplicación didFinishLaunchingWithOptions.
Respuesta actualizada para iOS 12 para verificar si top> 24 en lugar de top> 0.
Editar: en el simulador puede ir a Hardware, Activar barra de estado de llamada entrante. Hacer eso me muestra que la altura de la barra de estado no cambia en el iPhone X en iOS 11 o iPhone XS iOS 12 cuando se realiza una llamada. Todo lo que cambia es el ícono de tiempo, que obtiene un fondo verde, en ambos casos. Aquí hay un complemento:
Por lo general, el programador lo necesita para limitar la parte superior o inferior, por lo que estos métodos pueden ayudar
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
}
Para antes del iPhone X, estos métodos regresan: 0
Para iPhone X: 44 y 34 en consecuencia
Luego solo agregue estos extras a las restricciones superiores o inferiores
Puede hacer esto para detectar el dispositivo iPhone X según la dimensión.
Rápido
if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {
//iPhone X
}
C objetivo
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.nativeBounds.size.height == 2436) {
//iPhone X
}
Pero
Esto no es suficiente. ¿Qué pasaría si Apple anunciara el próximo iPhone con la misma dimensión que el iPhone X? Entonces, la mejor manera es usar una cadena de hardware para detectar el dispositivo.
Para el dispositivo más nuevo, la cadena de hardware es la siguiente.
iPhone 8 - iPhone10,1 o iPhone 10,4
iPhone 8 Plus - iPhone10,2 o iPhone 10,5
iPhone X - iPhone10,3 o iPhone10,6
Sé que es solo una solución Swift , pero podría ayudar a alguien.
Tengo
globals.swift
en cada proyecto y una de las cosas que siempre agrego es
DeviceType
para detectar fácilmente el dispositivo del usuario:
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
}
}
Luego para usarlo:
if DeviceType.hasNotch {
print("This executes on all phones with a notch")
}
if DeviceType.iPhone678 {
print("This executes on iPhones 6, 7 and 8")
}
Si usa
LaunchImage
en su proyecto, asegúrese de agregar imágenes para todos los dispositivos compatibles (como XS Max, XR) porque
UIScreen.main.bounds
no devolverá el valor adecuado sin ellos.
Sí, es posible. Descargue la extensión UIDevice-Hardware (o instálela a través de ''UIDevice-Hardware'' de CocoaPod) y luego use:
NSString* modelID = [[[UIDevice currentDevice] modelIdentifier];
BOOL isIphoneX = [modelID isEqualToString:@"iPhone10,3"] || [modelID isEqualToString:@"iPhone10,6"];
Tenga en cuenta que esto no funcionará en el simulador, solo en el dispositivo real.
Según la respuesta de @ saswanb, esta es una versión de Swift 4:
var iphoneX = false
if #available(iOS 11.0, *) {
if ((UIApplication.shared.keyWindow?.safeAreaInsets.top)! > CGFloat(0.0)) {
iphoneX = true
}
}
Según su pregunta, la respuesta es no. No hay métodos directos. Para obtener más información, puede obtener la información aquí:
y
La altura del iPhone X es de 2436 px
Desde tamaños de pantalla del dispositivo y resoluciones :
Desde los tamaños y orientaciones de la pantalla del dispositivo :
Swift 3 y posterior :
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")
}
}
Objetivo-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");
}
}
Basado en su pregunta de la siguiente manera:
O use
screenSize.height
como float
812.0f
no 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");
}
Para obtener más información, puede consultar la siguiente página en las Directrices de interfaz humana de iOS:
Rápido :
Detectar con
topNotch
:
var hasTopNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
Objetivo-C :
- (BOOL)hasTopNotch {
if (@available(iOS 11.0, *)) {
return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
}
return NO;
}
ACTUALIZACIÓN
No utilice la propiedad
userInterfaceIdiom
para identificar el tipo de dispositivo, como explica la
documentación de userInterfaceIdiom
:
Para aplicaciones universales, puede usar esta propiedad para adaptar el comportamiento de su aplicación para un tipo específico de dispositivo. Por ejemplo, los dispositivos iPhone y iPad tienen diferentes tamaños de pantalla, por lo que es posible que desee crear diferentes vistas y controles según el tipo de dispositivo actual.
Es decir, esta propiedad solo se usa para identificar el estilo de vista de la aplicación en ejecución.
Sin embargo, la aplicación para iPhone (no la universal) podría instalarse en el dispositivo iPad a través de la tienda de aplicaciones, en ese caso, el
userInterfaceIdiom
también devolverá el
UIUserInterfaceIdiomPhone
.
La forma correcta es obtener el nombre de la máquina a través de
uname
.
Verifique lo siguiente para más detalles:
Todas estas respuestas basadas en dimensiones son susceptibles de comportamiento incorrecto en dispositivos futuros. Funcionarán hoy, pero ¿qué pasa si el próximo año hay un iPhone del mismo tamaño pero tiene la cámara, etc. debajo del cristal para que no haya "muesca"? Si la única opción es actualizar la aplicación, entonces es una solución pobre para usted y sus clientes.
También puede verificar la cadena del modelo de hardware como "iPhone10,1", pero eso es problemático porque a veces Apple lanza diferentes números de modelo para diferentes operadores de todo el mundo.
El enfoque correcto es rediseñar el diseño superior o resolver los problemas que tiene con la altura de la barra de navegación personalizada (eso es en lo que me enfocaría). Pero, si decide no hacer ninguna de esas cosas, tenga en cuenta que lo que sea que esté haciendo es un truco para que esto funcione hoy , y tendrá que corregirlo en algún momento, tal vez varias veces, para mantener los trucos. trabajando.
Todas las respuestas que usan la
height
son solo la mitad de la historia por una razón.
Si va a verificar de esa manera cuando la orientación del dispositivo sea
landscapeLeft
o
landscapeRight
la verificación fallará, porque la
height
se intercambia con el
width
.
Es por eso que mi solución se ve así en 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
}
}
Verifique el nombre del modelo / máquina del dispositivo , NO use el recuento de puntos / píxeles en su código directamente, es un código duro y no tiene sentido para el hardware del dispositivo.
#import <sys/utsname.h>
NSString* deviceName()
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}
Resultado:
@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)
Refiérase a esta respuesta .
Implementación de código completo:
#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
}
Extensión reutilizable SWIFT 4
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
}
}
Swift 3 + 4:
sin necesidad de ningún valor de píxel de tamaño de dispositivo
//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
}
}
Ejemplo:
if UIApplication.isDeviceWithSafeArea {
//e.g. change the frame size height of your UITabBar
}
SWIFT 4+ Respuesta
iPhone X, XR, XS, XSMAX:
Nota: necesita un dispositivo real para la prueba
Reference
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
}
}
#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)
defina IS_IPHONE_X (límites de IS_IPHONE && [[UIScreen mainScreen]] .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"]
Nota: Tenga cuidado, funciona bien solo para orientación vertical
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 812.0f)
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
}
- (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;
}
}