Ios iPhone X将对象底部与安全区域对齐会破坏其他设备的外观

Ios iPhone X将对象底部与安全区域对齐会破坏其他设备的外观,ios,iphone,autolayout,iphone-x,Ios,Iphone,Autolayout,Iphone X,关于iPhoneX自动布局怪癖的问题 我有两个按钮,之前这些按钮将与superview底部对齐,偏移量为20,以使它们不接触屏幕底部(此后我将链接更改为安全区域而不是superview) 以下是原始设置: 在旧版iPhone上看起来和预期的一样好。 现在底部的20常量约束使得按钮看起来很时髦,而且离iPhoneX上的主工具栏太远。 从逻辑上讲,我需要从iPhoneX的约束中删除20常量,并使按钮直接与安全区域的底部对齐。 现在在iPhoneX上看起来不错。 但现在,它把按钮放在离屏幕底

关于iPhoneX自动布局怪癖的问题

我有两个按钮,之前这些按钮将与superview底部对齐,偏移量为20,以使它们不接触屏幕底部(此后我将链接更改为安全区域而不是superview)

以下是原始设置:

在旧版iPhone上看起来和预期的一样好。

现在底部的20常量约束使得按钮看起来很时髦,而且离iPhoneX上的主工具栏太远。

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

现在在iPhoneX上看起来不错。

但现在,它把按钮放在离屏幕底部太近的非家庭酒吧手机上。

我在苹果文档中遗漏的这个问题有什么即时解决方案吗?无法使用大小类,因为在本例中,iPhone X大小类与其他iPhone重叠

我可以很容易地为iphonex编写代码进行检测,并将约束上的常量设置为0,但我希望有一个更优雅的解决方案


谢谢,

苹果文档声明iOS 11中有一个新的声明可以解决这个问题。目前,iPhoneX和iPhone8的大小相同,因此我们必须想出另一种解决方案

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模拟器-详细信息屏幕

iPhone8模拟器-主屏幕

iPhone8模拟器-详细信息屏幕


另一种直接从故事板实现这一点的方法是创建两个约束:
1.在您的元素和安全区域之间,具有250优先级,且0常数
2.在您的元素和superview底部之间,具有750优先级和20常量且
大于或等于关系


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

解决方案是,当安全区域插入更改时,检查视图是否与具有非零安全区域的窗口对齐,并基于此调整约束的底部偏移到安全区域。以下情况导致矩形屏幕与底部的偏移量为20磅,安全区域屏幕(iPhone X、最新iPad Pro、iPad滑盖等)的全屏偏移量为0磅

//在UIView子类中,或在UIViewController中使用ViewSafeAreaInsettsDidChange而不是SafeAreaInsettsDidChange
@可用(iOS 11.0,*)
重写函数safeAreaInsetsDidChange(){
super.safeareainsertsdidchange()
IstakingCareofWindows安全区域=self.is在非车窗底部安全区域内
}
私有变量IstakingCareofWinowsAfearea=false{
迪塞特{
guard IstakingCareofWindows安全区域!=oldValue else{return}
//不同的补偿取决于我们是否关心安全区域
let offset:CGFloat=IstakingCareofWinowsAfearea?0:20
//bottomConstraint是视图安全区域所需的底部约束。
bottomConstraint.constant=-offset
}
}
扩展UIView{ ///允许您检查视图是否直接处理窗口的安全区域。原因是它是窗口而不是 ///屏幕是指iPad上的滑动应用程序等也有非零安全区域。基本上,任何没有正方形区域的东西(比如原来的带有矩形屏幕的iPhone)。 @可用(iOS 11.0,*) var为InnozeroWindowBottomSafeArea:Bool{ 让视图=自我 //如果我们不在窗户里就保释 guard let window=view.window else{return false} 让windowBottomSafeAreaInset=window.safeAreaInsets.bottom //如果我们的窗户没有底部安全区域的嵌入物,就要保释 guard windowBottomSafeAreaInset>0其他{返回false} //如果我们的底部区域与窗户的底部不匹配,就保释——其他的东西正在处理这个问题 guard windowBottomSafeAreaInset==view.safeAreaInsets.BottomElse{return false} //将边界转换为窗口以获得窗口内的帧 让viewFrameInWindow=view.convert(view.bounds,to:window) //如果底部与窗口对齐,则为true //注意:可以在这里添加额外的逻辑,例如一个回旋余地或其他什么 让isMatchingBottomFrame=viewFrameInWindow.maxY==window.frame.maxY 返回isMatchingBottomFrame } }
有一个“relative to Margin”选项,它至少可以让您不必指定丑陋的硬编码常量,例如
20
。然而,它仍然不能解决你的问题(我检查过)…我想这就是它将要发生的事情。苹果公司表示,安全区域在主栏上方一段距离。就我个人而言,我认为这看起来不错,也许你只是需要适应它。否则,如果您关闭视图上的安全区域相对边距,那么您可以使用底部的20点空间来获得与iPhone X和其他设备相似的外观。评论不错。希望有一个内置的方法来解释这一点。我想,生活在基于设备的it或硬编码约束下可能是一条出路。这个解决方案非常有效。我只需要再加一张支票