【问题标题】:Enable safe areas programmatically以编程方式启用安全区域
【发布时间】:2018-05-26 09:38:31
【问题描述】:

有没有办法以编程方式启用安全区域?

上下文:我正在开发的应用程序以 iOS 7 为目标,并且可能暂时不会改变。除非我放弃 iOS 7 和 8 的兼容性,否则 Xcode 不会接受启用的安全区域。大多数视图是 XIB。一个有条件启用的安全区域将是理想的。

【问题讨论】:

  • 我将objective-c 作为您帖子的标签,因为我假设您没有领先于您的时间。根据需要进行更改。
  • @LinusGeffarth Swift 不适用于 iOS 7
  • 这就是重点 ;)
  • @LinusGeffarth 不完全正确。 Swift 2确实支持 iOS 7。
  • 伙计们,我只是说我将objective-c作为标签b / c我认为OP可能使用它并让OP知道,以便他们在必要时进行更改。

标签: ios cocoa-touch ios-autolayout safearealayoutguide


【解决方案1】:

对 Xib 的条件安全区域支持

不,不存在多平台 Xib 之类的东西。您可以尝试复制您的 Xib,将它们独立构建为 Nib,并根据 iOS 版本在运行时有条件地访问它们,但当然不建议这样做!您将需要处理两倍以上的 Xib 和复杂性。根据 safeAreaInsets 对 Superview 设置约束并从代码中更改其常量要容易得多。

对代码的实际安全区域支持

Add iPhone X layout support to old Xcode 7 / Swift 2 project类似的情况:

获得安全区域支持的唯一方法是使用 Xcode 9 构建。因此,您必须放弃对 iOS 7 和 Swift 2 的支持。

一旦你使用了 Xcode 9,那么你可能会有条件代码:

斯威夫特

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)
    }
}

请注意,在第一段代码中我默认返回UIEdgeInsets.zero,在最后一段代码中我默认返回UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0):这只是一个选择问题,具体取决于您要如何处理它,因为Apple选择在 iOS 11 和 iOS 12 之间重新定义,给兼容性带来了很大的痛苦。

【讨论】:

    猜你喜欢
    • 2018-05-25
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多