我的应用程序针对无框设备(iPhoneX,Xs Xs max,Xr)有一些逻辑。目前它基于设备的型号工作,所以我通过DeviceKit框架检测型号。
但是我想将这种逻辑扩展到未来的无框设备上。可能在一年内我们会有一些额外的无框设备。那么,我该如何检测设备是否是无框的?它应该涵盖所有当前的无框设备和未来的设备。
我们无法依赖FaceID、safeAreaInset、屏幕高度或大小。那么,怎么办呢?
我的应用程序针对无框设备(iPhoneX,Xs Xs max,Xr)有一些逻辑。目前它基于设备的型号工作,所以我通过DeviceKit框架检测型号。
但是我想将这种逻辑扩展到未来的无框设备上。可能在一年内我们会有一些额外的无框设备。那么,我该如何检测设备是否是无框的?它应该涵盖所有当前的无框设备和未来的设备。
我们无法依赖FaceID、safeAreaInset、屏幕高度或大小。那么,怎么办呢?
var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
支持Swift 5和iOS 14
感谢@Tanin和@DominicMDev,由于且iPad Pro存在非零safeAreaInsets,这对我来说可以正常工作。
(已在、和iPad Pro (11英寸) (第2代)模拟器上测试通过)
extension UIDevice {
/// Returns `true` if the device has a notch
var hasNotch: Bool {
guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({$0.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
}
}
}
使用示例:
print(UIDevice.current.hasNotch)
UIDevice.current.orientation.isPortrait
始终返回 false,而 window.safeAreaInsets.left
等于 0。我在 iPhone 11 上测试了这个问题。奇怪的是,模拟器上该条件却正确运行。 - Nikhil Muskur自从在iOS 13中keyWindow已被弃用
,根据从这里找到的解决方案,这个方法对我有用
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
return keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
keyWindow?.safeAreaInsets.bottom == 20
,由于它没有底部按钮。最终我使用了"Saafo"的答案。 - Vladimir Amiorkov这适用于任何方向。 无需担心iOS版本在11.0之前的问题,因为iPhone X的最低版本是11.0。来源
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
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
}
}
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
}
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 {
guard #available(iOS 11.0, *), let window = UIApplication.shared.windows.filter({$0.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
}
}
}
对于使用场景代理的SwiftUI:
var hasNotch: Bool {
guard let scene = UIApplication.shared.connectedScenes.first,
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
let window = windowSceneDelegate.window else {
return false
}
return window?.safeAreaInsets.top ?? 0 > 20
}
}
enum DeviceInterfaceType {
case dynamicIsland
case notch
case none
}
extension UIDevice {
var interfaceType: DeviceInterfaceType {
guard let window = (UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.flatMap { $0.windows }.first { $0.isKeyWindow}) else {
return .none
}
if window.safeAreaInsets.top >= 51 && userInterfaceIdiom == .phone {
return .dynamicIsland
} else if window.safeAreaInsets.top >= 44 {
return .notch
} else if window.safeAreaInsets.left > 0 || window.safeAreaInsets.right > 0 {
return .none
}
return .none
}
}
switch UIDevice.current.interfaceType {
case .dynamicIsland:
//
case .notch:
//
case .none:
//
}