1

几个月前我从这个 SO question 得到了以下扩展,我想把它翻译成 NSLayoutAnchor (或更详细的布局 API),原因很简单,视觉格式不支持指定安全区域布局指南。

链接中的扩展名是这个:

extension UIView {

    /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
    /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
    func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
            print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
            return
        }

        self.translatesAutoresizingMaskIntoConstraints = false
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
    }
}

我的视图层次结构是:

UINavigationController -> 根视图控制器:UIPageViewController -> 第一页:UIViewController -> UIScrollView -> UIImageView

当我打电话bindFrameToSuperviewBounds()时,结果如下:

在此处输入图像描述

看起来大部分都很好。问题是图像视图位于导航栏下方,这是我不想要的。所以为了解决这个问题,我试图重写bindFrameToSuperviewBounds()为:

guard let superview = self.superview else {
            fatalError("Attempting to bound to a non-existing superview.")
        }

translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.trailingAnchor).isActive = true

结果是这样的:

在此处输入图像描述

这次它正确地没有进入导航栏,但是...您可以看到它被拉伸了,这是我不想要的。

将可视布局 API 转换为可以考虑安全区域布局指南的正确方法是什么?

为了完整起见,设置滚动视图和图像视图的代码如下:

override func viewDidLoad() {
    super.viewDidLoad()
    imageScrollView.addSubview(imageView)
    imageScrollView.layoutIfNeeded()
    imageView.bindFrameToSuperviewBounds()
    view.addSubview(imageScrollView)
    imageView.layoutIfNeeded()
    imageScrollView.backgroundColor = .white
    imageScrollView.bindFrameToSuperviewBounds()
    imageScrollView.delegate = self
}
4

2 回答 2

1

使用 Fattie 提供的代码,我能够得出这个解决方案:

guard let superview = self.superview else {
    fatalError("Attempting to bound to a non-existing superview.")
}

translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor).isActive = true

(现在我只是将顶部锚定到安全布局是指南。这是否会给 iPhone X 带来问题还有待观察)。

这给出了我期望的结果:

在此处输入图像描述

于 2017-10-22T00:54:49.640 回答
1

老实说,我不会为奇怪的“视觉”布局而烦恼,它们很快就会消失。

这有帮助吗?

extension UIView {

    // put this view "inside" it's superview, simply stretched all four ways
    // amazingly useful

    func bindEdgesToSuperview() {

        guard let s = superview else {
            preconditionFailure("`superview` nil in bindEdgesToSuperview")
        }

        translatesAutoresizingMaskIntoConstraints = false
        leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
        trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
        topAnchor.constraint(equalTo: s.topAnchor).isActive = true
        bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
    }

}

就这样用..

    textOnTop = ..  UILabel or whatever
    userPhoto.addSubview(textOnTop)
    textOnTop.bindEdgesToSuperview()

简单的 !

(PS - 不要忘记,如果它是一个图像:你几乎肯定想要设置为AspectFit,在所有情况下始终如此。)

安全布局指南的手柄就像...

.safeAreaLayoutGuide
于 2017-10-22T00:26:13.007 回答