我的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/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
    }
   }
}

其他回答

或者,你也可以查看“DeviceKit”pod。 安装完成后,检查设备所需要做的就是:

import DeviceKit
let device = Device()
if device == .iPhoneX {
  // place your code here
}

我知道这只是一个快速的解决方案,但它可以帮助一些人。

我在每个项目中都有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")
}

仅在竖屏中,我使用视图框架的宽度和高度来检查:

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

我认为苹果不希望我们手动检查设备是否有“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就有一个很大的顶部安全插件。在我的代码中,所有的情况都被占用(即使设备以纵向或横向启动)

根据你的问题,答案是否定的。没有直接的方法。欲了解更多信息,您可以在这里获得信息:

如何在iOS上获得设备制作和模型?

and

如何通过swift编程检查iPhone 4和iPhone 5的屏幕大小

iPhone X的高度是2436像素

从设备屏幕尺寸和分辨率:

从设备屏幕尺寸和方向:

Swift 3及以后:

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/11 Pro")
        
        case 2688:
            print("iPhone XS Max/11 Pro Max")
        
        case 1792:
            print("iPhone XR/ 11 ")
        
        default:
            print("Unknown")
        }
    }

objective - 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:
            case 2208:
                printf("iPhone 6+/6S+/7+/8+");
                break;

           case 2436:
                printf("iPhone X/XS/11 Pro");
                 break;

            case 2688:
                printf("iPhone XS Max/11 Pro Max");
                 break;

            case 1792:
                printf("iPhone XR/ 11 ");
                 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, 11 Pro");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 2688) {
        Console.WriteLine("iPhone XS Max, 11 Pro Max");
    } else if ((UIScreen.MainScreen.Bounds.Height * UIScreen.MainScreen.Scale) == 1792) {
        Console.WriteLine("iPhone XR, 11");
    } else {
        Console.WriteLine("Unknown");
    }
}

根据你的问题如下:

或者使用screenSize。高度为float 812.0f而不是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");
    }

有关更多信息,您可以参考以下页面的iOS人机界面指南:

适应性和布局-视觉设计- iOS -人机界面指南

迅速:

用topNotch检测:

如果有人考虑使用notch来检测iPhoneX,请注意,在“横向”上,它对所有iphone都是一样的。

var hasTopNotch: Bool {
    if #available(iOS 13.0,  *) {
        return UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.safeAreaInsets.top ?? 0 > 20
    }else{
     return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
    }

    return false
}

objective - c:

- (BOOL)hasTopNotch {
   if (@available(iOS 13.0, *)) {
       return [self keyWindow].safeAreaInsets.top > 20.0;
   }else{
       return [[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0;
   }
   return  NO;
}

- (UIWindow*)keyWindow {
    UIWindow        *foundWindow = nil;
    NSArray         *windows = [[UIApplication sharedApplication]windows];
    for (UIWindow   *window in windows) {
        if (window.isKeyWindow) {
            foundWindow = window;
            break;
        }
    }
    return foundWindow;
}

更新:

不要使用userInterfaceIdiom属性来识别设备类型,正如userInterfaceIdiom的文档解释的那样:

对于通用应用程序,您可以使用此属性为特定类型的设备定制应用程序的行为。例如,iPhone和iPad设备具有不同的屏幕尺寸,因此您可能希望根据当前设备的类型创建不同的视图和控件。

也就是说,这个属性只是用来识别正在运行的应用程序的视图样式。然而,iPhone应用程序(不是通用的)可以通过app store安装在iPad设备上,在这种情况下,userInterfaceIdiom也将返回UIUserInterfaceIdiomPhone。

正确的方法是通过uname获取机器名。详情请查阅以下资料:

如何在iOS上获得设备制作和模型?