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 将对象底部对齐到安全区域废墟在其他设备上的外观的主要内容,如果未能解决你的问题,请参考以下文章