问题
I am trying to find the top constraint of the view in code. The top constraint is added in storyboard, and I don't want to use an IBOutlet.
Logging the value of the firstAttribute in the following code seems to always return a constraint of type NSLayoutAttributeHeight. Any idea how I could reliably find a top constraint of a view in code?
NSLayoutConstraint *topConstraint;
for (NSLayoutConstraint *constraint in self.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeTop) {
topConstraint = constraint;
break;
}
}
回答1:
Instead of iterating through self.constraints
, you should iterate through self.superview.constraints
.
The self.constraints
only contain constraints related to just the view (e.g. height and width constraints).
Here's a code example of what this might look like:
- (void)awakeFromNib
{
[super awakeFromNib];
if (!self.topConstraint) {
[self findTopConstraint];
}
}
- (void)findTopConstraint
{
for (NSLayoutConstraint *constraint in self.superview.constraints) {
if ([self isTopConstraint:constraint]) {
self.topConstraint = constraint;
break;
}
}
}
- (BOOL)isTopConstraint:(NSLayoutConstraint *)constraint
{
return [self firstItemMatchesTopConstraint:constraint] ||
[self secondItemMatchesTopConstraint:constraint];
}
- (BOOL)firstItemMatchesTopConstraint:(NSLayoutConstraint *)constraint
{
return constraint.firstItem == self && constraint.firstAttribute == NSLayoutAttributeTop;
}
- (BOOL)secondItemMatchesTopConstraint:(NSLayoutConstraint *)constraint
{
return constraint.secondItem == self && constraint.secondAttribute == NSLayoutAttributeTop;
}
回答2:
I usually set an identifier
of a required constraint in the IB and then find it in the code like this (Swift):
if let index = constraints.index(where: { $0.identifier == "checkmarkLeftMargin" }) {
checkmarkImageViewLeftMargin = constraints[index]
}
OR by @Tim Vermeulen
checkmarkImageViewLeftMargin = constraints.first { $0.identifier == "checkmarkLeftMargin" }
回答3:
Using swift and UIView extension
extension UIView {
func findConstraint(layoutAttribute: NSLayoutAttribute) -> NSLayoutConstraint? {
if let constraints = superview?.constraints {
for constraint in constraints where itemMatch(constraint: constraint, layoutAttribute: layoutAttribute) {
return constraint
}
}
return nil
}
func itemMatch(constraint: NSLayoutConstraint, layoutAttribute: NSLayoutAttribute) -> Bool {
if let firstItem = constraint.firstItem as? UIView, let secondItem = constraint.secondItem as? UIView {
let firstItemMatch = firstItem == self && constraint.firstAttribute == layoutAttribute
let secondItemMatch = secondItem == self && constraint.secondAttribute == layoutAttribute
return firstItemMatch || secondItemMatch
}
return false
}
}
回答4:
Set the identifier in the inspector in Xcode. That's what it's for. You name it. If that's not enough you create the IBOutlet.
回答5:
Based on @Igor answer, I changed a bit itemMatch method to consider when first item or second item is not a UIView. For example when constraint a UIView top to safe area top.
extension UIView {
func findConstraint(layoutAttribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint? {
if let constraints = superview?.constraints {
for constraint in constraints where itemMatch(constraint: constraint, layoutAttribute: layoutAttribute) {
return constraint
}
}
return nil
}
func itemMatch(constraint: NSLayoutConstraint, layoutAttribute: NSLayoutConstraint.Attribute) -> Bool {
let firstItemMatch = constraint.firstItem as? UIView == self && constraint.firstAttribute == layoutAttribute
let secondItemMatch = constraint.secondItem as? UIView == self && constraint.secondAttribute == layoutAttribute
return firstItemMatch || secondItemMatch
}
}
回答6:
I write a small extension in Swift:
extension UIButton {
var topConstraints: [NSLayoutConstraint]? {
return self.constraints.filter( { ($0.firstItem as? UIButton == self && $0.firstAttribute == .top) || ($0.secondItem as? UIButton == self && $0.secondAttribute == .top) })
}
}
来源:https://stackoverflow.com/questions/26833641/ios-find-top-constraint-for-a-view