如何"找到"自己的约束?

Fat*_*tie 16 ios nslayoutconstraint swift

说我有一个UIView,

 class CleverView: UIView
Run Code Online (Sandbox Code Playgroud)

在自定义类中,我想这样做:

func changeWidth() {

  let c = ... find my own layout constraint, for "width"
  c.constant = 70 * Gameinfo.ImportanceOfEnemyFactor
}
Run Code Online (Sandbox Code Playgroud)

同样地,我希望能够像这样"找到",约束(或者我猜,所有约束,可能有不止一个)附加到四个边缘之一.

因此,要查看附加到我身上的所有约束,并找到任何宽度/高度,或者确实与给定(例如,"左")边缘相关的任何约束.

有任何想法吗?

也许值得注意这个问题


请注意(显然)我问如何动态/编程地执行此操作.

(是的,你可以说"链接到约束"或"使用ID" - 质量保证的重点是如何动态地找到它们并动态地工作.)

如果您不熟悉约束,请注意.constraints只是为您提供存储在那里的结尾.

sta*_*kri 22

实际上有两种情况:

  1. 关于视图大小或与后代视图的关系的约束本身被保存
  2. 两个视图之间的约束保存在视图的最低共同祖先中

重复.对于两个视图之间的约束.事实上,iOS确实将它们存储在最低的共同祖先中.因此,通过搜索视图的所有祖先,总是可以找到视图的约束.

因此,我们需要检查视图本身及其所有超视图的约束.一种方法可能是:

extension UIView {

    // retrieves all constraints that mention the view
    func getAllConstraints() -> [NSLayoutConstraint] {

        // array will contain self and all superviews
        var views = [self]

        // get all superviews
        var view = self
        while let superview = view.superview {
            views.append(superview)
            view = superview
        }

        // transform views to constraints and filter only those
        // constraints that include the view itself
        return views.flatMap({ $0.constraints }).filter { constraint in
            return constraint.firstItem as? UIView == self ||
                constraint.secondItem as? UIView == self
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在获得关于视图的所有约束之后,您可以应用所有类型的过滤器,我想这是最困难的部分.一些例子:

extension UIView {

    // Example 1: Get all width constraints involving this view
    // We could have multiple constraints involving width, e.g.:
    // - two different width constraints with the exact same value
    // - this view's width equal to another view's width
    // - another view's height equal to this view's width (this view mentioned 2nd)
    func getWidthConstraints() -> [NSLayoutConstraint] {
        return getAllConstraints().filter( {
            ($0.firstAttribute == .width && $0.firstItem as? UIView == self) ||
            ($0.secondAttribute == .width && $0.secondItem as? UIView == self)
        } )
    }

    // Example 2: Change width constraint(s) of this view to a specific value
    // Make sure that we are looking at an equality constraint (not inequality)
    // and that the constraint is not against another view
    func changeWidth(to value: CGFloat) {

        getAllConstraints().filter( {
            $0.firstAttribute == .width &&
                $0.relation == .equal &&
                $0.secondAttribute == .notAnAttribute
        } ).forEach( {$0.constant = value })
    }

    // Example 3: Change leading constraints only where this view is
    // mentioned first. We could also filter leadingMargin, left, or leftMargin
    func changeLeading(to value: CGFloat) {
        getAllConstraints().filter( {
            $0.firstAttribute == .leading &&
                $0.firstItem as? UIView == self
        }).forEach({$0.constant = value})
    }
}
Run Code Online (Sandbox Code Playgroud)

//编辑:增强的示例并在评论中阐明了他们的解释


Pun*_*rma 9

我猜你可以使用约束属性UIView.constraints基本上返回一个直接赋给UIView的约束数组.它不能让你获得超级视图所包含的约束,例如前导,尾随,顶部或底部,但宽度和高度约束由View本身保持.对于superview的约束,您可以遍历superview的约束.让我们说聪明的观点有这些限制:

在此输入图像描述

class CleverView: UIView {

    func printSuperViewConstriantsCount() {
        var c = 0
        self.superview?.constraints.forEach({ (constraint) in
            guard constraint.secondItem is CleverView || constraint.firstItem is CleverView else {
                return
            }
            c += 1
            print(constraint.firstAttribute.toString())
        })
        print("superview constraints:\(c)")
    }

    func printSelfConstriantsCount() {
        self.constraints.forEach { (constraint) in
            return print(constraint.firstAttribute.toString())
        }
        print("self constraints:\(self.constraints.count)")
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

顶部
领先
尾随
上海华约束:3
高度
自我约束:1

基本上,您可以查看NSLayoutConstraint类以获取有关特定约束的信息.

要打印约束的名称,我们可以使用此扩展名

extension NSLayoutAttribute {
    func toString() -> String {
        switch self {
        case .left:
            return "left"
        case .right:
            return "right"
        case .top:
            return "top"
        case .bottom:
            return "bottom"
        case .leading:
            return "leading"
        case .trailing:
            return "trailing"
        case .width:
            return "width"
        case .height:
            return "height"
        case .centerX:
            return "centerX"
        case .centerY:
            return "centerY"
        case .lastBaseline:
            return "lastBaseline"
        case .firstBaseline:
            return "firstBaseline"
        case .leftMargin:
            return "leftMargin"
        case .rightMargin:
            return "rightMargin"
        case .topMargin:
            return "topMargin"
        case .bottomMargin:
            return "bottomMargin"
        case .leadingMargin:
            return "leadingMargin"
        case .trailingMargin:
            return "trailingMargin"
        case .centerXWithinMargins:
            return "centerXWithinMargins"
        case .centerYWithinMargins:
            return "centerYWithinMargins"
        case .notAnAttribute:
            return "notAnAttribute"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)