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

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


当前回答

我试图使工作之前的答复,他们都没有为我工作。所以我为SwiftUI找到了一个解决方案。创建名为UIDevice+Notch.swift的文件

其内容:

extension UIDevice {
    var hasNotch: Bool {
        let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
        return bottom > 0
    }
}

用法:

if UIDevice.current.hasNotch {
    //... consider notch 
} else {
    //... don't have to consider notch 
}

其他回答

我正在使用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

我依靠状态栏框架高度来检测它是否是iPhone X:

if UIApplication.shared.statusBarFrame.height >= CGFloat(44) {
    // It is an iPhone X
}

这是为应用程序unportrait。您还可以根据设备方向检查大小。另外,在其他iphone上,状态栏可能是隐藏的,因此帧高为0。在iPhone X上,状态栏永远不会隐藏。

所有这些基于尺寸的答案都很容易在未来的设备上出现错误行为。它们今天还能用,但如果明年有一款同样大小的iPhone,但在玻璃下面有摄像头等,所以没有“缺口”呢?如果唯一的选择是更新应用程序,那么这对你和你的客户来说都是一个糟糕的解决方案。

您还可以检查硬件型号字符串,如“iPhone10,1”,但这是有问题的,因为有时苹果会为世界各地的不同运营商发布不同的型号。

正确的方法是重新设计顶部布局,或者解决自定义导航栏高度的问题(这是我关注的重点)。但是,如果你决定不做这两件事中的任何一件,你要意识到无论你现在做什么都是为了让它工作,你需要在某个时候纠正它,也许是多次,以保持它工作。

有几个原因让我们想知道这个设备是什么。

您可以检查设备的高度(和宽度)。这对布局很有用,但如果你想知道确切的设备,你通常不想这样做。 为了布局的目的,你也可以使用UIView.safeAreaInsets。 如果您想显示设备名称,例如,为了诊断目的,在使用sysctl()检索设备模型后,您可以使用等效的此方法来计算名称: $ curl http://appledevicenames.com/devices/iPhone10,6 iPhone X

struct ScreenSize {
    static let width = UIScreen.main.bounds.size.width
    static let height = UIScreen.main.bounds.size.height
    static let maxLength = max(ScreenSize.width, ScreenSize.height)
    static let minLength = min(ScreenSize.width, ScreenSize.height)
    static let frame = CGRect(x: 0, y: 0, width: ScreenSize.width, height: ScreenSize.height)
}

struct DeviceType {
    static let iPhone4orLess = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength < 568.0
    static let iPhone5orSE = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 568.0
    static let iPhone678 = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 667.0
    static let iPhone678p = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 736.0
    static let iPhoneX = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.maxLength == 812.0

    static let IS_IPAD              = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1024.0
    static let IS_IPAD_PRO          = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.maxLength == 1366.0
}