我的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功能),还是我必须使用间接测量?”

根据目前给出的答案,我假设答案是“不,没有直接的方法。测量是要走的路。”


当前回答

下面是Objective-C中需要的两个宏。

#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_IPHONE_X (IS_IPHONE && [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 24.0)

用法:

if (IS_IPHONE_X) {
}

我希望它能帮助别人。

其他回答

#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)

定义IS_IPHONE_X (IS_IPHONE && [[UIScreen mainScreen] bounds].size。身高== 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"]

注意:-小心,它只适用于纵向方向

检查设备型号/机器名称,不要在你的代码中直接使用点/像素计数,这是硬代码,对设备硬件没有意义,设备型号是设备类型匹配的唯一标识符。

#import <sys/utsname.h>

NSString* deviceName()
{
    struct utsname systemInfo;
    uname(&systemInfo);

    return [NSString stringWithCString:systemInfo.machine
                          encoding:NSUTF8StringEncoding];
}

结果:

@"iPhone10,3" on iPhone X (CDMA)
@"iPhone10,6" on iPhone X (GSM)

参考这个答案。

完整的代码实现:

#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)
{
    NSArray<NSString *> *notchiModels = @[
        @"iPhone10,3", @"iPhone10,6", // iPhone X
        @"iPhone11,2", @"iPhone11,4", @"iPhone11,6", // iPhone XS (Max)
        @"iPhone11,8", // iPhone XR
        @"iPhone12,1", @"iPhone12,3", @"iPhone12,5", // iPhone 11 (Pro (Max))
        @"iPhone13,1", @"iPhone13,2", @"iPhone13,3", @"iPhone13,4", // iPhone 12 ([mini]|[Pro (Max)])
    ];

    return [notchiModels containsObject:GetDeviceModel()];
}

我正在使用Peter Kreinz的代码(因为它是干净的,做了我需要的),但后来我意识到它只在设备是纵向的时候工作(因为顶部填充将在顶部,显然) 所以我创建了一个扩展来处理所有的方向与它各自的填充,而不依赖于屏幕大小:

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
    }
}

在你的电话网站上

let res = UIDevice.current.isIphoneX

使用简单的方法检测任何设备。像下面,

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
}

像这样叫,

if isPhoneDevice() {
     // Your code
}

为了快速解决问题,我喜欢这样:

let var:CGFloat = (UIDevice.current.userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436) ? <iPhoneX> : <AllOthers>