iOS:检测设备是否为iPhone X系列(无框)
iOS: Detect if the device is iPhone X family (frameless)
在我的应用程序中有一些针对无框设备(iPhoneX、Xs Xs max、Xr)的逻辑。目前它基于设备模型工作,因此,我通过 DeviceKit 框架检测模型。
但我想将此逻辑扩展到未来的无框设备。可能在一年内我们将有一些额外的无框设备。那么,如何检测设备是否无框?它应该涵盖所有当前和未来的无框设备。
我们不能依赖 faceID、safeAreaInset、屏幕高度或尺寸。那么,然后呢?
您可以 "fitler" 获得一流的成绩,例如:
var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
这样你就可以涵盖所有方向了:
var hasTopNotch: Bool
{
if #available(iOS 11.0, *) {
var safeAreaInset: CGFloat?
if (UIApplication.shared.statusBarOrientation == .portrait) {
safeAreaInset = UIApplication.shared.delegate?.window??.safeAreaInsets.top
}
else if (UIApplication.shared.statusBarOrientation == .landscapeLeft) {
safeAreaInset = UIApplication.shared.delegate?.window??.safeAreaInsets.left
}
else if (UIApplication.shared.statusBarOrientation == .landscapeRight) {
safeAreaInset = UIApplication.shared.delegate?.window??.safeAreaInsets.right
}
return safeAreaInset ?? 0 > 24
}
return false
}
这对任何方向都有效。
无需担心 iOS 11.0 之前的版本,因为 iPhone X 最低版本为 11.0。 Source
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
我这样做是因为 iPadPro 有非零的 safeAreaInsets。
extension UIDevice {
/// Returns 'true' if the device has a notch
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.keyWindow else { return false }
let orientation = UIApplication.shared.statusBarOrientation
if orientation.isPortrait {
return window.safeAreaInsets.top >= 44
} else {
return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
}
}
}
extension UIDevice {
var hasNotch: Bool
{
if #available(iOS 11.0, *)
{
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
} else
{
// Fallback on earlier versions
return false
}
}
}
使用者
if UIDevice.current.hasNotch
{
//... consider notch
}
else
{
//... don't have to consider notch
}
Swift 5
var hasNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
} else {
return false
}
}
因为 keyWindow was deprecated in iOS 13
,基于从 中找到 keyWindow
的解决方案,这个对我有用
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
let keyWindow = UIApplication.shared.windows.filter {[=10=].isKeyWindow}.first
return keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
Swift5个,iOS14个支持
感谢@Tanin 和@DominicMDev,因为 keyWindow was deprecated in iOS 13
和 the iPad Pro has non-zero safeAreaInsets
,这对我来说很好。
(已在 iPhone 8
、iPhone 11 Pro
和 iPad Pro (11-inch)(2nd gen)
模拟器上测试)
extension UIDevice {
/// Returns `true` if the device has a notch
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first else { return false }
if UIDevice.current.orientation.isPortrait {
return window.safeAreaInsets.top >= 44
} else {
return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
}
}
}
extension UIDevice {
var hasNotch: Bool {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
}
}
使用 'UIDevice.current.hasNotch' 将 return 正确或错误
Swift 5
var hasNotch: Bool {
let bottom = UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0
return bottom > 0
}
safeTop = UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0
if safeTop > 20 {
print("Big family")
} else {
print("Before X")
}
Swift 5.0
最简单易懂,适合你的情况。
因为 ⚠️设备方向 != 界面方向 ⚠️
我的最终代码是:
extension UIDevice {
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first else { return false }
//if UIDevice.current.orientation.isPortrait { //Device Orientation != Interface Orientation
if let o = windowInterfaceOrientation?.isPortrait, o == true {
return window.safeAreaInsets.top >= 44
} else {
return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
}
}
private var windowInterfaceOrientation: UIInterfaceOrientation? {
if #available(iOS 13.0, *) {
return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
} else {
return UIApplication.shared.statusBarOrientation
}
}
}
var hasNotch: Bool {
if #available(iOS 11.0, *) {
if UIApplication.shared.windows.count == 0 { return false } // Should never occur, but…
let top = UIApplication.shared.windows[0].safeAreaInsets.top
return top > 20 // That seem to be the minimum top when no notch…
} else {
// Fallback on earlier versions
return false
}
}
func isIphoneX() -> Bool {
guard #available(iOS 11.0, *),
let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first else { return false }
return window.safeAreaInsets.top >= 44
}
如果您想检查 UIViewController 中的缺口,只需在方法 viewSafeAreaInsetsDidChange() 中设置 isNotch 标志
open override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
isNotch = true
}
我只在模拟器上测试过。它仅在所有方向的 X 设备中调用。
在我的应用程序中有一些针对无框设备(iPhoneX、Xs Xs max、Xr)的逻辑。目前它基于设备模型工作,因此,我通过 DeviceKit 框架检测模型。
但我想将此逻辑扩展到未来的无框设备。可能在一年内我们将有一些额外的无框设备。那么,如何检测设备是否无框?它应该涵盖所有当前和未来的无框设备。
我们不能依赖 faceID、safeAreaInset、屏幕高度或尺寸。那么,然后呢?
您可以 "fitler" 获得一流的成绩,例如:
var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
这样你就可以涵盖所有方向了:
var hasTopNotch: Bool
{
if #available(iOS 11.0, *) {
var safeAreaInset: CGFloat?
if (UIApplication.shared.statusBarOrientation == .portrait) {
safeAreaInset = UIApplication.shared.delegate?.window??.safeAreaInsets.top
}
else if (UIApplication.shared.statusBarOrientation == .landscapeLeft) {
safeAreaInset = UIApplication.shared.delegate?.window??.safeAreaInsets.left
}
else if (UIApplication.shared.statusBarOrientation == .landscapeRight) {
safeAreaInset = UIApplication.shared.delegate?.window??.safeAreaInsets.right
}
return safeAreaInset ?? 0 > 24
}
return false
}
这对任何方向都有效。 无需担心 iOS 11.0 之前的版本,因为 iPhone X 最低版本为 11.0。 Source
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
我这样做是因为 iPadPro 有非零的 safeAreaInsets。
extension UIDevice {
/// Returns 'true' if the device has a notch
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.keyWindow else { return false }
let orientation = UIApplication.shared.statusBarOrientation
if orientation.isPortrait {
return window.safeAreaInsets.top >= 44
} else {
return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
}
}
}
extension UIDevice {
var hasNotch: Bool
{
if #available(iOS 11.0, *)
{
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
} else
{
// Fallback on earlier versions
return false
}
}
}
使用者
if UIDevice.current.hasNotch
{
//... consider notch
}
else
{
//... don't have to consider notch
}
Swift 5
var hasNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
} else {
return false
}
}
因为 keyWindow was deprecated in iOS 13
,基于从 keyWindow
的解决方案,这个对我有用
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
let keyWindow = UIApplication.shared.windows.filter {[=10=].isKeyWindow}.first
return keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
Swift5个,iOS14个支持
感谢@Tanin 和@DominicMDev,因为 keyWindow was deprecated in iOS 13
和 the iPad Pro has non-zero safeAreaInsets
,这对我来说很好。
(已在 iPhone 8
、iPhone 11 Pro
和 iPad Pro (11-inch)(2nd gen)
模拟器上测试)
extension UIDevice {
/// Returns `true` if the device has a notch
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first else { return false }
if UIDevice.current.orientation.isPortrait {
return window.safeAreaInsets.top >= 44
} else {
return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
}
}
}
extension UIDevice {
var hasNotch: Bool {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
}
}
使用 'UIDevice.current.hasNotch' 将 return 正确或错误
Swift 5
var hasNotch: Bool {
let bottom = UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0
return bottom > 0
}
safeTop = UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0
if safeTop > 20 {
print("Big family")
} else {
print("Before X")
}
Swift 5.0 最简单易懂,适合你的情况。
因为 ⚠️设备方向 != 界面方向 ⚠️
我的最终代码是:
extension UIDevice {
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first else { return false }
//if UIDevice.current.orientation.isPortrait { //Device Orientation != Interface Orientation
if let o = windowInterfaceOrientation?.isPortrait, o == true {
return window.safeAreaInsets.top >= 44
} else {
return window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0
}
}
private var windowInterfaceOrientation: UIInterfaceOrientation? {
if #available(iOS 13.0, *) {
return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
} else {
return UIApplication.shared.statusBarOrientation
}
}
}
var hasNotch: Bool {
if #available(iOS 11.0, *) {
if UIApplication.shared.windows.count == 0 { return false } // Should never occur, but…
let top = UIApplication.shared.windows[0].safeAreaInsets.top
return top > 20 // That seem to be the minimum top when no notch…
} else {
// Fallback on earlier versions
return false
}
}
func isIphoneX() -> Bool {
guard #available(iOS 11.0, *),
let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first else { return false }
return window.safeAreaInsets.top >= 44
}
如果您想检查 UIViewController 中的缺口,只需在方法 viewSafeAreaInsetsDidChange() 中设置 isNotch 标志
open override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
isNotch = true
}
我只在模拟器上测试过。它仅在所有方向的 X 设备中调用。