我的iOS应用程序为UINavigationBar使用了自定义高度,这在新的iPhone X上导致了一些问题。
是否有人已经知道如何通过编程(在Objective-C中)可靠地检测应用程序是否在iPhone X上运行?
编辑:
当然,检查屏幕的大小是可能的,但是,我想知道是否有一些“内置”的方法,如TARGET_OS_IPHONE来检测iOS…
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812)
NSLog(@"iPhone X");
}
编辑2:
我不认为,我的问题是一个重复的关联问题。当然,有一些方法可以“测量”当前设备的不同属性,并使用结果来决定使用哪种设备。然而,这并不是我在第一篇编辑中试图强调的问题的实际意义。
真正的问题是:“是否有可能直接检测当前设备是否是iPhone X(例如通过某些SDK功能),还是我必须使用间接测量?”
根据目前给出的答案,我假设答案是“不,没有直接的方法。测量是要走的路。”
所有使用高度的答案都只是故事的一半,原因只有一个。如果你想这样检查当设备朝向是landscapeLeft或landscape ight时检查会失败,因为高度和宽度互换了。
这就是为什么我的解决方案看起来像这样在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
}
}
SWIFT 4/5可重用扩展,支持iPhone 12
extension UIDevice {
enum `Type` {
case iPhone_5_5S_5C_SE1
case iPhone_6_6S_7_8_SE2
case iPhone_6_6S_7_8_PLUS
case iPhone_X_XS_12mini
case iPhone_XR_11
case iPhone_XS_11Pro_Max
case iPhone_12_Pro
case iPhone_12_Pro_Max
}
var hasHomeButton: Bool {
switch type {
case . iPhone_X_XS_12mini, . iPhone_XR_11, .iPhone_XS_11Pro_Max, . iPhone_XS_11Pro_Max, .iPhone_12_Pro, .iPhone_12_Pro_Max:
return false
default:
return true
}
}
var type: Type {
if UI_USER_INTERFACE_IDIOM() == .phone {
switch UIScreen.main.nativeBounds.height {
case 1136:
return .iPhone_5_5S_5C_SE1
case 1334:
return .iPhone_6_6S_7_8_SE2
case 1920, 2208:
return .iPhone_6_6S_7_8_PLUS
case 2436:
return .iPhone_X_XS_12mini
case 2532:
return .iPhone_12_Pro
case 2688:
return .iPhone_XS_11Pro_Max
case 2778:
return .iPhone_12_Pro_Max
case 1792:
return .iPhone_XR_11
default:
assertionFailure("Unknown phone device detected!")
return .iPhone_6_6S_7_8_SE2
}
} else {
assertionFailure("Unknown idiom device detected!")
return .iPhone_6_6S_7_8_SE2
}
}
}
我详细阐述了你对其他人的回答,并在UIDevice上进行了快速扩展。我喜欢快速枚举和“一切有序”&原子化。我已经创建了解决方案,工作在设备和模拟器。
优点:
-界面简单,使用方法如UIDevice.current.isIPhoneX
- UIDeviceModelType enum让你能够轻松地扩展模型特定的特性和你想在你的应用中使用的常量,例如拐角半径
劣势:
-这是特定于型号的解决方案,而不是特定于分辨率的解决方案-例如,如果苹果将生产另一种具有相同规格的型号,这将无法正常工作,你需要添加另一种型号才能使其工作=>你需要更新你的应用程序。
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
}
}
在看完所有的答案后,我最后是这么做的:
解决方案(兼容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
}
}
Use
if UIDevice.isIphoneX {
// is iPhoneX
} else {
// is not iPhoneX
}
Note
Pre Swift 4.1你可以检查应用程序是否在模拟器上运行,就像这样:
TARGET_OS_SIMULATOR != 0
从Swift 4.1开始,你可以使用目标环境平台条件检查应用程序是否在模拟器上运行:
#if targetEnvironment(simulator)
return true
#else
return false
#endif
(旧的方法仍然有效,但这个新方法更经得起未来的考验)