В моем приложении есть логика для безрамочных устройств (iPhoneX, Xs Xs max, Xr). В настоящее время он работает на основе модели устройств, поэтому я определяю модель по фреймворку DeviceKit.
Но я хочу распространить эту логику на будущие безрамочные устройства. Возможно, через год у нас появятся лишние безрамочные устройства. Итак, как я могу определить, является ли устройство безрамочным или нет? Он должен охватывать все текущие безрамочные устройства и будущие.
Мы не можем полагаться на faceID, safeAreaInset, высоту или размер экрана. Так что же тогда?
@Cristik, да, я знаю это
Apple не выпускает много разных моделей под управлением iOS, поэтому просто обновляйте список устройств по мере их выхода. Я предполагаю, что это будет около 10 минут работы в год.
@slickdaddy, приложение предназначено для клиентов, и они не хотят выкладывать много обновлений, я хочу сэкономить их время
см. это, например: stackoverflow.com/questions/46192280/…
см. stackoverflow.com/a/52821290/3472073





Вы бы «отфильтровали» по высшему разряду, например:
var hasTopNotch: Bool {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
Это не работает для iPad Pro, где statusBarHeight равен 24pt.
MarekR -> попробуйте ".bottom вместо .top"
Таким образом, вы можете охватить все ориентации:
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. Источник
extension UIDevice {
var hasNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
keyWindow теперь устарела.
Я делаю это так, потому что 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 {$0.isKeyWindow}.first
return keyWindow?.safeAreaInsets.bottom ?? 0 > 0
}
return false
}
}
Swift 5, поддерживается iOS 14
Благодаря @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({$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
}
}
}
@NikhilMuskur Я пробовал на iPhone 8 Plus, iPhone 12 Pro и iPad Pro (11 дюймов) на iOS 14.1, Xcode 12.1 только что, и он работает хорошо. Какое у вас состояние?
В симуляторе все работает правильно, но когда я запускаю это на устройстве, свойство isPortrait всегда ложно.
@NikhilMuskur, можешь ли ты дать более точное описание своей ситуации? На каком устройстве и как вы указали, что свойство isPortrait всегда ложно?
Во время отладки я обнаружил, что UIDevice.current.orientation.isPortrait всегда возвращал false, а window.safeAreaInsets.left был равен 0. Я тестировал это на iPhone 11. Как ни странно, условие правильно работает на симуляторе.
@NikhilMuskur Ну, я тестировал на своем iPhone X, и UIDevice.current.orientation.isPortrait работает хорошо (верните true, когда портрет) ...
Могу подтвердить, не работает, для rootViewController UIVindow, позже - он работает
extension UIDevice {
var hasNotch: Bool {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
}
}
используйте 'UIDevice.current.hasNotch' вернет истину или ложь
Swift 5
var hasNotch: Bool {
let bottom = UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0
return bottom > 0
}
это хорошая практика - защищать свой код, подумайте о добавлении описания к вашему ответу
Также опишите, чем ваш ответ отличается от 8 существующих ответов.
Не принимайте решения в приложении в зависимости от размера экрана. Он просто не масштабируется и его сложно поддерживать.