LoginSignup
0
1

More than 3 years have passed since last update.

任意の方向の NSLayoutConstraint を UIView から取得する

Posted at

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 で事足りるように思う。

0
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1