Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import UIKit
protocol NSLayoutConstraintSearchable: class {}
extension NSLayoutConstraintSearchable {
// this function does add support for UIView and UILayoutGuide
private func getConstraints() -> [NSLayoutConstraint]? {
// only UIView's hold constraints
if let owningView = (self as? UILayoutGuide)?.owningView {
return owningView.constraints
} else if let view = self as? UIView {
return view.constraints
}
return nil
}
func searchConstraintWith(attribute attribute1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation? = nil, toItem item: AnyObject? = nil, attribute attribute2: NSLayoutAttribute? = nil) -> NSLayoutConstraint? {
// self is used as `firstItem` in this function
// constraints are hold by `firstItem` OR `secondItem`
guard let constraints = self.getConstraints() else {
// there is something wrong when our private function can't return any constraints
return nil
}
// convert to a set so we can use `union` function if the second item is defined and returns any constraints
var constraintsSet = Set(constraints)
if let constraints = (item as? NSLayoutConstraintSearchable)?.getConstraints() {
// union constraints from second item if possible
constraintsSet = constraintsSet.union(constraints)
}
// find all constraints with the same relation (if specified)
let filteredConstraints = constraintsSet.filter {
if let unwrappedRelation = relation {
return $0.relation == unwrappedRelation
}
return true
}
// iterate constraints where `firstItem` is `self` and `firstAttribute` equals given `attribute1`
for constraint in filteredConstraints.filter({ $0.firstItem === self && $0.firstAttribute == attribute1}) {
// check if the `secondAttribute` is specified (nil means we will ignore the value)
if let secondAttribute = attribute2 {
// skip until `secondAttribute` does equal given attribute
guard constraint.secondAttribute == secondAttribute else { continue }
// skip any constraint where the `secondItem` does not equal specified `item`
if let unwrappedItem = item where constraint.secondItem !== unwrappedItem { continue }
// return constraint when `item` equals `secondItem` or swallow if `item` is nil
return constraint
} else /* ignore `secondAttribute` in all constraints */ {
// skip any constraint where the `secondItem` does not equal specified `item`
if let unwrappedItem = item where constraint.secondItem !== unwrappedItem { continue }
// return constraint when `item` equals `secondItem` or swallow if `item` is nil
return constraint
}
}
// do the same as above but with reversed item and attribute order
// item and attribute order does not matter for constraints (except: firstItem & firstAttribute vs. secondItem & secondAttribute)
for constraint in filteredConstraints.filter({ $0.secondItem === self && $0.secondAttribute == attribute1}) {
if let secondAttribute = attribute2 {
guard constraint.firstAttribute == secondAttribute else { continue }
if let unwrappedItem = item where constraint.firstItem !== unwrappedItem { continue }
return constraint
} else {
if let unwrappedItem = item where constraint.firstItem !== unwrappedItem { continue }
return constraint
}
}
// no constraint found with given parameter
return nil
}
}
extension UIView: NSLayoutConstraintSearchable {}
extension UILayoutGuide: NSLayoutConstraintSearchable {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment