iPhone X 将对象底部与安全区域对齐会破坏其他设备上的外观
iPhone X Aligning object bottom to Safe Area ruins look on other devices
关于 iPhone X Autolayout 怪癖的问题。
我有两个按钮,以前它们会与超级视图底部对齐,偏移量为 20,以免它们接触屏幕底部(我已经将 link 更改为安全区域,而不是超级视图)。
这是原始设置:
在旧版 iPhone 上看起来不错。
现在底部约束上的 20 常量现在使按钮看起来很时髦并且离 iPhone X 上的主页栏太远。
从逻辑上讲,我需要从 iPhone X 的约束中删除 20 常量,并让按钮直接与安全区域的底部对齐。
现在在 iPhone X 上看起来不错。
但现在它在非家庭酒吧电话上将按钮放置得太靠近屏幕底部。
我在 Apple 文档中遗漏了这个问题的任何直接解决方案?不能使用尺寸 classes,因为在这种情况下 iPhone X 尺寸 class 与其他 iPhones 重叠。
我可以轻松地编写代码来检测 iPhone X 并将约束上的常量设置为 0,但我希望有一个更优雅的解决方案。
谢谢,
Apple 文档指出 iOS11 中有一个新的声明可以解决这个问题。目前 iPhone X 和 iPhone 8 共享相同的大小 class 所以我们必须想出另一个解决方案。
var additionalSafeAreaInsets: UIEdgeInsets { 设置 }
在您的 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 Interface Builder 与安全区域对齐
iPhone 8 Interface Builder 对齐到安全区域
iPhone X 模拟器 - 主屏幕
iPhone X 模拟器 - 详细信息屏幕
iPhone 8 模拟器 - 主屏幕
iPhone 8 模拟器 - 详细信息屏幕
另一种直接从故事板实现这一点的方法是创建两个约束:
1. 在你的元素和安全区域之间,优先级为 250,常量为 0
2. 在你的元素和 superview 底部之间具有 750 优先级和 20 常量和 greater Than or Equal
关系。
在花了相当多的时间尝试解决这种类型的问题后,最初使用 ,我 运行 遇到了一个没有解决问题的情况 - 特别是在以下情况下"safe area" 是非零高度但不是屏幕的安全区域意味着偏移量是 0 而不是最小值 20。示例是通过 additionalSafeAreaInsets
设置底部安全区域的任意视图控制器。
解决方案是在安全区域insets变化时检查我们的视图是否与window非零安全区域对齐,并根据此调整约束的底部偏移到安全区域。以下导致矩形样式屏幕底部偏移20pt,安全区域样式屏幕全屏为0(iPhone X,最新iPad Pro,iPad slide旁白等)。
// 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 Autolayout 怪癖的问题。
我有两个按钮,以前它们会与超级视图底部对齐,偏移量为 20,以免它们接触屏幕底部(我已经将 link 更改为安全区域,而不是超级视图)。
这是原始设置:
在旧版 iPhone 上看起来不错。
现在底部约束上的 20 常量现在使按钮看起来很时髦并且离 iPhone X 上的主页栏太远。
从逻辑上讲,我需要从 iPhone X 的约束中删除 20 常量,并让按钮直接与安全区域的底部对齐。
现在在 iPhone X 上看起来不错。
但现在它在非家庭酒吧电话上将按钮放置得太靠近屏幕底部。
我在 Apple 文档中遗漏了这个问题的任何直接解决方案?不能使用尺寸 classes,因为在这种情况下 iPhone X 尺寸 class 与其他 iPhones 重叠。
我可以轻松地编写代码来检测 iPhone X 并将约束上的常量设置为 0,但我希望有一个更优雅的解决方案。
谢谢,
Apple 文档指出 iOS11 中有一个新的声明可以解决这个问题。目前 iPhone X 和 iPhone 8 共享相同的大小 class 所以我们必须想出另一个解决方案。
var additionalSafeAreaInsets: UIEdgeInsets { 设置 }
在您的 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 Interface Builder 与安全区域对齐
iPhone 8 Interface Builder 对齐到安全区域
iPhone X 模拟器 - 主屏幕
iPhone X 模拟器 - 详细信息屏幕
iPhone 8 模拟器 - 主屏幕
iPhone 8 模拟器 - 详细信息屏幕
另一种直接从故事板实现这一点的方法是创建两个约束:
1. 在你的元素和安全区域之间,优先级为 250,常量为 0
2. 在你的元素和 superview 底部之间具有 750 优先级和 20 常量和 greater Than or Equal
关系。
在花了相当多的时间尝试解决这种类型的问题后,最初使用 additionalSafeAreaInsets
设置底部安全区域的任意视图控制器。
解决方案是在安全区域insets变化时检查我们的视图是否与window非零安全区域对齐,并根据此调整约束的底部偏移到安全区域。以下导致矩形样式屏幕底部偏移20pt,安全区域样式屏幕全屏为0(iPhone X,最新iPad Pro,iPad slide旁白等)。
// 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
}
}