我的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功能),还是我必须使用间接测量?”
根据目前给出的答案,我假设答案是“不,没有直接的方法。测量是要走的路。”
不要像其他解决方案建议的那样使用屏幕像素大小,这很糟糕,因为它可能会导致未来设备出现假阳性;将不工作,如果UIWindow尚未渲染(AppDelegate),将不工作在景观应用程序,并可以失败在模拟器上,如果比例设置。
相反,我已经为此目的做了一个宏,它非常容易使用,并依赖于硬件标志来防止上述问题。
编辑:更新到支持iPhoneX, iPhoneXS, iPhoneXR, iPhoneXS Max
使用方法:
if (IS_DEVICE_IPHONEX) {
//do stuff
}
是的,真的。
宏:
复制粘贴到任何地方,我更喜欢@end后的。h文件的底部
#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]);\
})()\
)
仅在竖屏中,我使用视图框架的宽度和高度来检查:
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")
}
}
竖屏尺寸列在这里
更新
这个答案已经过时了,现在iPhone阵容中有更多的X系列,你要么必须在if-else中列出所有这些尺寸,要么检查设备是否有缺口会更容易。大约1.5年前,我从某个地方得到了这个答案/代码。如果我能链接到代码,我会的。
// 1. add an extension to UIDevice with this computed property
extension UIDevice {
var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
}
// 2. to use in any class
override func viewDidLoad() {
super.viewDidLoad()
if UIDevice.current.hasTopNotch {
print("X series")
} else {
print("regular phone")
}
}
我知道这只是一个快速的解决方案,但它可以帮助一些人。
我在每个项目中都有global .swift,有一些代码来简化我的生活,我总是添加的一件事是ScreenSize和hasNotch,可以轻松检测手机类型和尺寸:
struct ScreenSize {
static let width = UIScreen.main.bounds.size.width
static let height = UIScreen.main.bounds.size.height
}
var hasNotch: Bool {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 0
}
然后使用它:
if hasNotch {
print("This executes on all phones with a notch")
}
所有使用高度的答案都只是故事的一半,原因只有一个。如果你想这样检查当设备朝向是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
}
}