以编程方式启用安全区域
Enable safe areas programmatically
有没有办法以编程方式启用安全区域?
上下文:我正在开发的应用程序坚持 iOS 7 作为目标,这可能暂时不会改变。 Xcode 不接受启用安全区域,除非我放弃 iOS 7 和 8 兼容性。大多数视图是 XIB。有条件启用的安全区域将是理想的选择。
Xib 的条件安全区域支持
不,没有多平台 Xib 这样的东西。您可能会尝试复制您的 Xib,将它们独立构建为 Nib,并根据 iOS 版本在运行时有条件地访问它们,但当然不建议这样做!您需要处理两倍的 Xib 和复杂性。根据 safeAreaInsets 对 Superview 施加约束并从代码更改它们的常量要容易得多。
代码的实际安全区域支持
与类似的情况:
获得安全区域支持的唯一方法是使用 Xcode 9 进行构建。因此您 必须放弃 对 iOS 7 和 [=51 的支持=] 2.
一旦你使用 Xcode 9,那么你可能有条件代码:
Swift
extension UIApplication {
class var safeAreaInsets: UIEdgeInsets {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets ?? UIEdgeInsets.zero
}
return UIEdgeInsets.zero
}
}
ObjC
@interface UIApplication (extension)
+ (UIEdgeInsets)safeAreaInsets;
@end
@implementation UIApplication (extension)
+ (UIEdgeInsets)safeAreaInsets {
if (@available(iOS 11.0, tvOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.delegate.window;
return window != nil ? window.safeAreaInsets : UIEdgeInsetsZero;
}
return UIEdgeInsetsZero;
}
@end
代码的模拟安全区域支持
现在,让我们面对现实吧,要支持的设备形状并不多(只有三种情况:竖屏竖屏、竖屏竖屏、其他)。因此,您可以根据机器型号构建自己的安全区域值,它可能会帮助您使用旧版本的 Xcode:
extension UIApplication {
/// on iPhone X+ portrait: top : 44.0, left : 0.0, bottom : 34.0, right : 0.0
/// on iPhone X+ landscape: top : 0.0, left : 44.0, bottom : 21.0, right : 44.0
/// on olders: top : 20.0, left : 0.0, bottom : 0.0, right : 0.0
class var safeAreaInsetsSimulated: UIEdgeInsets {
let model: String
if TARGET_OS_SIMULATOR != 0 {
model = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
} else {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
model = String(cString: machine)
}
// will need adjustment in 2019
if model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,") {
switch UIApplication.shared.statusBarOrientation {
case .landscapeRight, .landscapeLeft:
return UIEdgeInsets(top: 0, left: 44, bottom: 21, right: 44)
default:
return UIEdgeInsets(top: 44, left: 0, bottom: 34, right: 0)
}
}
return UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
}
}
请注意,在第一段代码中我默认为 return UIEdgeInsets.zero
,而在最后一段代码中我默认为 return UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
:这只是一个选择的问题取决于你想如何处理它,因为 Apple 选择在 iOS 11 和 iOS 12 之间重新定义它,这给兼容性带来了很大的痛苦。
有没有办法以编程方式启用安全区域?
上下文:我正在开发的应用程序坚持 iOS 7 作为目标,这可能暂时不会改变。 Xcode 不接受启用安全区域,除非我放弃 iOS 7 和 8 兼容性。大多数视图是 XIB。有条件启用的安全区域将是理想的选择。
Xib 的条件安全区域支持
不,没有多平台 Xib 这样的东西。您可能会尝试复制您的 Xib,将它们独立构建为 Nib,并根据 iOS 版本在运行时有条件地访问它们,但当然不建议这样做!您需要处理两倍的 Xib 和复杂性。根据 safeAreaInsets 对 Superview 施加约束并从代码更改它们的常量要容易得多。
代码的实际安全区域支持
与
获得安全区域支持的唯一方法是使用 Xcode 9 进行构建。因此您 必须放弃 对 iOS 7 和 [=51 的支持=] 2.
一旦你使用 Xcode 9,那么你可能有条件代码:
Swift
extension UIApplication {
class var safeAreaInsets: UIEdgeInsets {
if #available(iOS 11.0, tvOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets ?? UIEdgeInsets.zero
}
return UIEdgeInsets.zero
}
}
ObjC
@interface UIApplication (extension)
+ (UIEdgeInsets)safeAreaInsets;
@end
@implementation UIApplication (extension)
+ (UIEdgeInsets)safeAreaInsets {
if (@available(iOS 11.0, tvOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.delegate.window;
return window != nil ? window.safeAreaInsets : UIEdgeInsetsZero;
}
return UIEdgeInsetsZero;
}
@end
代码的模拟安全区域支持
现在,让我们面对现实吧,要支持的设备形状并不多(只有三种情况:竖屏竖屏、竖屏竖屏、其他)。因此,您可以根据机器型号构建自己的安全区域值,它可能会帮助您使用旧版本的 Xcode:
extension UIApplication {
/// on iPhone X+ portrait: top : 44.0, left : 0.0, bottom : 34.0, right : 0.0
/// on iPhone X+ landscape: top : 0.0, left : 44.0, bottom : 21.0, right : 44.0
/// on olders: top : 20.0, left : 0.0, bottom : 0.0, right : 0.0
class var safeAreaInsetsSimulated: UIEdgeInsets {
let model: String
if TARGET_OS_SIMULATOR != 0 {
model = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? ""
} else {
var size = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
model = String(cString: machine)
}
// will need adjustment in 2019
if model == "iPhone10,3" || model == "iPhone10,6" || model.starts(with: "iPhone11,") {
switch UIApplication.shared.statusBarOrientation {
case .landscapeRight, .landscapeLeft:
return UIEdgeInsets(top: 0, left: 44, bottom: 21, right: 44)
default:
return UIEdgeInsets(top: 44, left: 0, bottom: 34, right: 0)
}
}
return UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
}
}
请注意,在第一段代码中我默认为 return UIEdgeInsets.zero
,而在最后一段代码中我默认为 return UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
:这只是一个选择的问题取决于你想如何处理它,因为 Apple 选择在 iOS 11 和 iOS 12 之间重新定义它,这给兼容性带来了很大的痛苦。