我的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功能),还是我必须使用间接测量?”
根据目前给出的答案,我假设答案是“不,没有直接的方法。测量是要走的路。”
SWIFT 4+回答
iPhone X, XR, XS, XSMAX, 11 Pro, 11 Pro Max:
注:需实物设备进行测试
参考
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")
case "iPhone12,3":
print("iPhone 11 Pro")
case "iPhone12,5":
print("iPhone 11 Pro Max")
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
}
}
另一种可能是,在iOS 11和iOS 12上都能运行,因为iPhone X是唯一一款顶部有凹槽、嵌框为44的手机。这就是我在这里真正发现的:
objective - c:
BOOL iPhoneX = NO;
if (@available(iOS 11.0, *)) {
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
if (mainWindow.safeAreaInsets.top > 24.0) {
iPhoneX = YES;
}
}
斯威夫特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
}
当然,如果你是在横向,你可能需要检查左右安全区域的嵌入。
Edit: _window是AppDelegate的UIWindow,这个检查在应用didFinishLaunchingWithOptions中完成。
iOS 12的答案更新,以检查顶部>是否为24,而不是顶部> 0。
编辑:在模拟器中,您可以选择硬件,切换通话状态栏。这样做表明,在通话时,iOS 11的iPhone X或iOS 12的iPhone XS上的状态栏高度没有变化。在这两种情况下,改变的只是时间图标,它的背景都是绿色的。这是一张快照:
不要像其他解决方案建议的那样使用屏幕像素大小,这很糟糕,因为它可能会导致未来设备出现假阳性;将不工作,如果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]);\
})()\
)
随着iOS 12的发布,像iPhone X这样的设备可能会被归入这一类别。
`
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
}
}`
我认为苹果不希望我们手动检查设备是否有“notch”或“home indicator”,但有效的代码是:
-(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;
}
其他一些帖子都没用。例如,竖屏模式下“通话状态栏”(绿色栏)的iPhone 6S就有一个很大的顶部安全插件。在我的代码中,所有的情况都被占用(即使设备以纵向或横向启动)