如果我在 运行 应用程序中使用 IBDesignable 文件,为什么自动布局不会更新?

why the autolayout is not updated if I use IBDesignable file when i run the app?

这里是这个问题在google驱动器中的项目:https://drive.google.com/file/d/1Js0t-stoerWy8O8uIOJl_bDw-bnWAZPr/view?usp=sharing

我使用下面的 IBDesignable 代码制作了一个自定义导航栏(下图中的红色视图)。我想,如果 iPhone 有像 iPhone X, iPhone XR 这样的顶级,那么自定义导航栏的高度是 88,否则高度是 64。我制作了一个 IBDesignable 代码我可以重用这段代码

import UIKit

@IBDesignable
class CustomParentNavigationBarView: UIView {

    override func awakeFromNib() {
        super.awakeFromNib()
        self.setHeight()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        self.setHeight()
    }

    func setHeight() {
        let deviceHasTopNotch = checkHasTopNotchOrNot()
        layer.frame.size.height = deviceHasTopNotch ? 88 : 64
    }

    func checkHasTopNotchOrNot() -> Bool {
        if #available(iOS 11.0, tvOS 11.0, *) {
            // with notch: 44.0 on iPhone X, XS, XS Max, XR.
            // without notch: 20.0 on iPhone 8 on iOS 12+.
            return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
        }
        return false
    }

}

我把这个CustomParentNavigationBarView分配给红色view

然后,我贴上标签。应该正好位于红色视图下方(自定义导航栏,使用 IBDesignable)

如果我 运行 iPhone 中的应用程序没有像 iPhone8 这样的顶级应用程序,它看起来很棒

但是,如果我 运行 iPhone 中具有像 iPhone XR 这样一流的应用程序,标签现在在红色视图中,它似乎仍然遵循之前的自动布局之前 64 的红色视图高度(在情节提要中我使用 iPhone 8),因此当自定义导航栏在 iPhone XR 上 运行ning 更新为 88 时,标签仍然按照之前的64高度,就会定位到红色view里面

这里是自定义导航栏的自动布局(红色视图)

这里是标签的自动布局

如何解决这个问题?

这里的问题是您在 setHeight() 中指定了框架高度,但也在故事板中指定了布局约束的高度。解决此问题的一种方法是为您的视图指定一个 intrinsicContentSize,而不是将高度指定为情节提要中的布局约束。 (I.o.w。类似于你依赖标签宽度的方式给你计算)

@IBDesignable
class CustomParentNavigationBarView: UIView {

    lazy var deviceHasTopNotch: Bool = {
        if #available(iOS 11.0, tvOS 11.0, *) {
            // with notch: 44.0 on iPhone X, XS, XS Max, XR.
            // without notch: 20.0 on iPhone 8 on iOS 12+.
            return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
        }
        return false
    }()

    override var intrinsicContentSize: CGSize {
        let height:CGFloat = deviceHasTopNotch ? 88 : 64
        let width = super.intrinsicContentSize.width //Use whatever you prefer here.  Ex.UIScreen.main.bounds.size.width
        return CGSize(width: width, height: height)
    }
}

在情节提要中

删除自定义视图的当前高度限制。将 Intrinsic Size 属性 设置为 Placeholder

自定义导航栏的布局约束示例。