, , Marcos, , - , " " , , 0 20. , additionalSafeAreaInsets
.
The solution was to check whether our view aligns with a window with a non-zero safe area when the inserts of the safe area change, and adjust the lower offset of the limit to the safe area based on this. The following leads to a shift of 20 points from the bottom of the screen in a rectangular style and 0 on a full-screen screen in the style of a safe zone (iPhone X, the latest iPad Pro, iPad sliders, etc.).
// 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 safe area. The reason it the window rather than
/// the screen is that on iPad, slide over apps and such also have this nonzero safe area. Basically anything that does not 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 does not have bottom safe area insets
guard windowBottomSafeAreaInset > 0 else { return false }
// Bail if our bottom area does not match the window 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
}
}
source
share