iPhone X 将对象底部对齐到安全区域废墟在其他设备上的外观

Posted

技术标签:

【中文标题】iPhone X 将对象底部对齐到安全区域废墟在其他设备上的外观【英文标题】:iPhone X Aligning object bottom to Safe Area ruins look on other devices 【发布时间】:2017-10-23 00:06:54 【问题描述】:

关于 iPhone X 自动布局怪癖的问题。

我有两个按钮,以前它们将与超级视图底部对齐,偏移量为 20,以免它们接触屏幕底部(我已经将链接更改为安全区域而不是超级视图)。

这是原始设置:

在旧款 iPhone 上看起来不错。

现在底部约束上的 20 常量现在使按钮看起来很时髦,并且离 iPhone X 上的主页栏太远了。

从逻辑上讲,我需要从 iPhone X 上的约束中删除 20 常量,并使按钮直接与安全区域的底部对齐。

现在在 iPhone X 上看起来不错。

但现在它把按钮放置在非家用酒吧手机的屏幕底部太近了。

我在 Apple 文档中遗漏的这个问题的任何直接解决方案?不能使用尺寸等级,因为在这种情况下 iPhone X 尺寸等级与其他 iPhone 重叠。

我可以轻松编写代码来检测 iPhone X 并将约束上的常量设置为 0,但我希望有一个更优雅的解决方案。

谢谢,

【问题讨论】:

有一个“相对于边距”选项,至少可以让您不必指定难看的硬编码常量,例如20。但是,它仍然不能解决您的问题(我检查过)... 我想事情就是这样。苹果表示,安全区域在主酒吧上方有一段距离。我个人认为它看起来不错,也许你只需要习惯它。否则,如果您关闭视图上的安全区域相对边距,那么您可以使用距底部 20 点的空间来获得与 iPhone X 和其他设备相似的外观。 好的cmets。希望有一个内置的方法来解决这个问题。我想与它一起生活或基于设备的硬编码约束可能是要走的路。 【参考方案1】:

另一种直接从情节提要中实现此目的的方法是创建两个约束: 1. 在您的元素和安全区域之间,优先级为 250,常量为 0 2.在你的元素和superview底部之间有750个优先级和20个常量和greater Than or Equal关系。

【讨论】:

很好的解决方案,在界面构建器上工作的绝佳选择,虽然不同设备上的界面构建器预览有时会显示错误的结果,但在运行模拟器上你可以看到它工作正常。【参考方案2】:

Apple Docs 指出 ios 11 中有一个新声明可以解决这个问题。目前 iPhone X 和 iPhone 8 共享相同的尺寸等级,所以我们必须想出另一个解决方案。

var additionalSafeAreaInsets: UIEdgeInsets get set

在您的 AppDelegate 中添加以下代码,rootViewController 的所有子级都将继承额外的安全区域。下面的示例屏幕截图描述了这种行为。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 
    // Override point for customization after application launch.

    if !self.isIphoneX() 
        self.window?.rootViewController?.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)
    

    return true


func isIphoneX() -> Bool 
    if #available(iOS 11.0, *) 
        if ((self.window?.safeAreaInsets.top)! > CGFloat(0.0)) 
            return true;
        
    
    return false

与安全区域对齐的 iPhone X 界面生成器

与安全区域对齐的 iPhone 8 界面生成器

iPhone X 模拟器 - 主屏幕

iPhone X 模拟器 - 详细信息屏幕

iPhone 8 模拟器 - 主屏幕

iPhone 8 模拟器 - 详细信息屏幕

【讨论】:

这个解决方案效果很好。在设置 AdditionalSafeAreaInsets 之前,我只需要在 didFinishLaunchingWithOptions 中添加对 iOS 11 的另一项检查。谢谢! window.safeAreaInsets.top 对我来说总是大于 0,在非 iPhone X 设备上也是如此。例如,在 iPhone 8 上,状态栏是 20。【参考方案3】:

在花了相当多的时间尝试解决此类问题(最初使用 Marcos's solution)后,我遇到了一个无法解决的情况 - 特别是在“安全区域”不是零高度但不是屏幕的安全区域意味着偏移量是 0 而不是最小值 20。示例是通过additionalSafeAreaInsets 设置底部安全区域的任意视图控制器。

解决的办法是在安全区域插入发生变化时,检查我们的视图是否与具有非零安全区域的窗口对齐,并据此调整约束的底部偏移到安全区域。以下导致在矩形样式屏幕中从底部偏移 20pt,在具有安全区域样式屏幕(iPhone X、最新 iPad Pro、iPad 幻灯片等)的全屏中偏移 0。

// In UIView subclass, or UIViewController using viewSafeAreaInsetsDidChange instead of safeAreaInsetsDidChange

@available(iOS 11.0, *)
override func safeAreaInsetsDidChange() 
    super.safeAreaInsetsDidChange()
    isTakingCareOfWindowSafeArea = self.isWithinNonZeroWindowBottomSafeArea


private var isTakingCareOfWindowSafeArea = false 
    didSet 
        guard isTakingCareOfWindowSafeArea != oldValue else  return 
        // Different offset based on whether we care about the safe area or not
        let offset: CGFloat = isTakingCareOfWindowSafeArea ? 0 : 20
        // bottomConstraint is a required bottom constraint to the safe area of the view.
        bottomConstraint.constant = -offset
    

extension UIView 

    /// Allows you to check whether the view is dealing directly with the window's safe area. The reason it's the window rather than
    /// the screen is that on iPad, slide over apps and such also have this nonzero safe area. Basically anything that doesn't have a square area (such as the original iPhones with rectangular screens).
    @available(iOS 11.0, *)
    var isWithinNonZeroWindowBottomSafeArea: Bool 

        let view = self

        // Bail if we're not in a window
        guard let window = view.window else  return false 
        let windowBottomSafeAreaInset = window.safeAreaInsets.bottom

        // Bail if our window doesn't have bottom safe area insets
        guard windowBottomSafeAreaInset > 0 else  return false 

        // Bail if our bottom area doesn't match the window's bottom - something else is taking care of that
        guard windowBottomSafeAreaInset == view.safeAreaInsets.bottom else  return false 

        // Convert our bounds to the window to get our frame within the window
        let viewFrameInWindow = view.convert(view.bounds, to: window)

        // true if our bottom is aligned with the window
        // Note: Could add extra logic here, such as a leeway or something
        let isMatchingBottomFrame = viewFrameInWindow.maxY == window.frame.maxY

        return isMatchingBottomFrame

    


【讨论】:

以上是关于iPhone X 将对象底部对齐到安全区域废墟在其他设备上的外观的主要内容,如果未能解决你的问题,请参考以下文章

为标签栏控制器和 iPhone X 实现安全区域

iPhone X - 设置主页指示器周围区域的颜色

Xamarin Forms - 如何让 TableView 和 ListView 扩展到 iPhone X 安全区域?

iPhone X 的“安全区域”(以像素为单位)是啥?

Ionic iPhone X 安全区域无法正常工作

iPhone X上的额外底部空间/填充?