在swift中为视图分配约束的最简单方法?

时间:2017-12-19 17:10:21

标签: ios swift uiview view constraints

我使用以下方法将视图添加为子视图并以编程方式添加其约束。 这就是我创建视图的方式:

// In class
let view: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

这就是我添加约束的方式:

addSubview(view)

view.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
view.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 100).isActive = true

是否有任何方法可以让我更轻松地实现这一目标或使用更少的代码行。我需要以编程方式创建约束,并且我不建议仅为此目的使用其他库。

5 个答案:

答案 0 :(得分:1)

您可以使用视觉格式语言。这样做可以获得简洁,但对于不了解语法的开发人员却会失去清晰度。

如果要使用VFL为视图设置上述约束,则代码如下:

var constraints = [NSLayoutConstraint]()
constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[view(100)]|", options: [], metrics: nil, views: ["view":view])
constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:[view(100)]", options: [], metrics: nil, views: ["view":view])
NSLayoutConstraint.activate(constraints)

正如您所看到的,对于这样一组简单的约束,您不会获得太多收益。但是,考虑到你必须构建一个复杂的UI,它对不同的对象有许多约束,所有这些都与彼此相关,VFL会使这样做更容易,更简洁。

VFL非常喜欢或讨厌它,尽管我建议你做一些阅读,这样你就可以做出明智的决定。 This RayWendelich指南特别有用。

答案 1 :(得分:1)

这不是更少的代码行,而是逐行.isActive = true,我发现activate更清洁一点:

NSLayoutConstraint.activate([
    view.leadingAnchor.constraint(equalTo: leadingAnchor),
    view.trailingAnchor.constraint(equalTo: trailingAnchor),
    view.widthAnchor.constraint(equalToConstant: 100),
    view.heightAnchor.constraint(equalToConstant: 100)
])

或者,如果你这么做,请编写自己的扩展名:

extension UIView {
    func activate(leading: NSLayoutAnchor<NSLayoutXAxisAnchor>? = nil,
                  trailing: NSLayoutAnchor<NSLayoutXAxisAnchor>? = nil,
                  top: NSLayoutAnchor<NSLayoutYAxisAnchor>? = nil,
                  bottom: NSLayoutAnchor<NSLayoutYAxisAnchor>? = nil,
                  centerX: NSLayoutAnchor<NSLayoutXAxisAnchor>? = nil,
                  centerY: NSLayoutAnchor<NSLayoutYAxisAnchor>? = nil,
                  width: CGFloat? = nil,
                  height: CGFloat? = nil) {
        translatesAutoresizingMaskIntoConstraints = false

        if let leading = leading   { leadingAnchor.constraint(equalTo: leading).isActive = true }
        if let trailing = trailing { trailingAnchor.constraint(equalTo: trailing).isActive = true }
        if let top = top           { topAnchor.constraint(equalTo: top).isActive = true }
        if let bottom = bottom     { bottomAnchor.constraint(equalTo: bottom).isActive = true }
        if let centerX = centerX   { centerXAnchor.constraint(equalTo: centerX).isActive = true }
        if let centerY = centerY   { centerYAnchor.constraint(equalTo: centerY).isActive = true }
        if let width = width       { widthAnchor.constraint(equalToConstant: width).isActive = true }
        if let height = height     { heightAnchor.constraint(equalToConstant: height).isActive = true }
    }
}

然后你可以用一行代码来完成它:

view.activate(leading: leadingAnchor, trailing: trailingAnchor, width: 100, height: 100)

答案 2 :(得分:0)

NSLayoutAnchor类使得编写AutoLayout代码变得更加容易,但仍然是冗长和重复的。您可以在UIView上创建扩展,并在AutoLayout周围添加包装,可以在所有UIViewControllers中使用。例如,我在

下面添加了尺寸和钉扎边缘的方法
extension UIView {

  func size(width: CGFloat, height: CGFloat) {
    NSLayoutConstraint.activate([
        self.widthAnchor.constraint(equalToConstant: width),
        self.heightAnchor.constraint(equalToConstant: height)
    ])
  }

  func edges(_ edges: UIRectEdge, to view: UIView, offset: UIEdgeInsets) {
    if edges.contains(.top) || edges.contains(.all) {
        self.topAnchor.constraint(equalTo: view.topAnchor, constant: offset.top).isActive = true
    }

    if edges.contains(.bottom) || edges.contains(.all) {
        self.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: offset.bottom).isActive = true
    }

    if edges.contains(.left) || edges.contains(.all) {
        self.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: offset.left).isActive = true
    }

    if edges.contains(.right) || edges.contains(.all) {
        self.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: offset.right).isActive = true
    }
  }
}

现在您只需使用2行

即可为视图设置约束
view.edges([.left, .right], to: self.view, offset: .zero)
view.size(width: 100, height: 100)

答案 3 :(得分:0)

我写下了一些我认为可以帮助所有开发人员的扩展。

extension UIView {

    func addView(view: UIView, top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets? = .zero, width: CGFloat?, height: CGFloat?) {

        view.translatesAutoresizingMaskIntoConstraints = false

        if !self.subviews.contains(view) {
            addSubview(view)
        }

        if let top = top {
            view.topAnchor.constraint(equalTo: top, constant: padding?.top ?? 0).isActive = true
        }
        if let leading = left {
            view.leadingAnchor.constraint(equalTo: leading, constant: padding?.left ?? 0).isActive = true
        }
        if let bottom = bottom {
            view.bottomAnchor.constraint(equalTo: bottom, constant: -(padding?.bottom ?? 0)).isActive = true
        }
        if let trailing = right {
            view.trailingAnchor.constraint(equalTo: trailing, constant: -(padding?.right ?? 0)).isActive = true
        }
        if let width = width, width != 0 {
            view.widthAnchor.constraint(equalToConstant: width).isActive = true
        }
        if let height = height, height != 0 {
            view.heightAnchor.constraint(equalToConstant: height).isActive = true
        }
    }

    func anchorSizeTo(width: NSLayoutDimension?,and height: NSLayoutDimension?) {
        if let width = width {
            self.widthAnchor.constraint(equalTo: width).isActive = true
        }
        if let height = height {
            self.heightAnchor.constraint(equalTo: height).isActive = true
        }
    }

    func anchorCenterTo(x: NSLayoutXAxisAnchor?, y: NSLayoutYAxisAnchor?,with padding: CGPoint = .zero) {
        if let anchor = x {
            self.centerXAnchor.constraint(equalTo: anchor, constant: padding.x).isActive = true
        }
        if let anchor = y {
            self.centerYAnchor.constraint(equalTo: anchor, constant: padding.y).isActive = true
        }
    }
}

用法:

superView.addView(view: subView, top: upperView.bottomAnchor, leading: leftView.trailingAnchor, bottom: superView.bottom, trailing: rightView.trailingAnchor, padding: UIEdgeInsetsMake(12, 12, 12, 12), width: 0, height: nil)

答案 4 :(得分:0)

除了Rob提到的NSLayoutConstraint.activate方法之外,您还可以使用更通用的方法来消除多个.isActive = true语句:

[
    view.leadingAnchor.constraint(equalTo: leadingAnchor),
    view.trailingAnchor.constraint(equalTo: trailingAnchor),
    view.widthAnchor.constraint(equalToConstant: 100),
    view.heightAnchor.constraint(equalToConstant: 100),
].forEach {$0.isActive = true}

将为数组的每个元素调用提供的内联函数(闭包){$0.isActive = true}

$0这是简写参数名称。在我们的例子中,它保存对数组元素的引用,即NSConstraint对象。