UIView#constraints
を探索すればいいのかと思ったら、superview のそれも探索しないといけない。
さらにいうと、その superview のそれも、と言った具合に再帰的に探索する必要がある。
のだが、実際的には自分とその親の分だけ探索すれば良いように思う。
そんなレイアウトの時は @IBOutlet しましょう。
UIView+Constraint.swift
import UIKit
public extension UIView {
private var meAndSuperviewConstraints: [NSLayoutConstraint] {
var meAndSuperviewConstraints = constraints
guard let superview = superview else {
return meAndSuperviewConstraints
}
allConstraints.append(contentsOf: superview.constraints)
return meAndSuperviewConstraints
}
private func firstConstraint(attribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint? {
return meAndSuperviewConstraints.first(where: {
(($0.firstItem as? UIView == self) && $0.firstAttribute == attribute)
|| (($0.secondItem as? UIView == self) && $0.secondAttribute == attribute)
})
}
var leftConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .left)
}
var rightConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .right)
}
var topConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .top)
}
var bottomConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .bottom)
}
var leadingConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .leading)
}
var trailingConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .trailing)
}
var widthConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .width)
}
var heightConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .height)
}
var centerXConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .centerX)
}
var centerYConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .centerY)
}
var lastBaselineConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .lastBaseline)
}
var firstBaselineConstraint: NSLayoutConstraint? {
return firstConstraint(attribute: .firstBaseline)
}
本気でやるなら、次のようになるでしょう
private func firstConstraint(attribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint? {
var constraints: [NSLayoutConstraint] = self.constraints
var view = self
while let superview = view.superview {
constraints.append(contentsOf: superview.constraints)
view = superview
}
return constraints.first(where: {
(($0.firstItem as? UIView == self) && $0.firstAttribute == attribute)
|| (($0.secondItem as? UIView == self) && $0.secondAttribute == attribute)
})
}
まあけど、そもそも runtime で constraint 取りたい場合ってすごく単純な制約の場合がほとんどな気がするので、ちょっと手抜きしたいって時のためなら、最初の extension で事足りるように思う。