I'm trying to animate a control in Cocoa with auto layout.
Now, I can set [[constraint animator] setConstant:newWidth];
, which works.
But how can I get the right constraint?
With [self constraints]
you can get all the constraints, and in this case I can just select constraints[0]
, but the order of the constraints may vary.
How can I be certain I always have the right constraint? The constraints are set in Interface Builder. I have seen that you can add a IBOutlet to it, but it doesn't seem necessary.
Thanks, it worked great. I wrote a little category.
#import <Cocoa/Cocoa.h>
@interface NSView (NSLayoutConstraintFilter)
- (NSLayoutConstraint *)constraintForAttribute:(NSLayoutAttribute)attribute;
- (NSArray *)constaintsForAttribute:(NSLayoutAttribute)attribute;
@end
#import "NSView+NSLayoutConstraintFilter.h"
@implementation NSView (NSLayoutConstraintFilter)
- (NSArray *)constaintsForAttribute:(NSLayoutAttribute)attribute {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstAttribute = %d", attribute];
NSArray *filteredArray = [[self constraints] filteredArrayUsingPredicate:predicate];
return filteredArray;
}
- (NSLayoutConstraint *)constraintForAttribute:(NSLayoutAttribute)attribute {
NSArray *constraints = [self constaintsForAttribute:attribute];
if (constraints.count) {
return constraints[0];
}
return nil;
}
@end
If you see the error message contains UIView-Encapsulated-Layout-Width , which means your constraints relative to width conflict with it. For example, you set label constrains: [ leading , trailing , bottom , top ] or [ CenterX , leading , bottom , top ] leading trailing and CenterX are for width.
If you want to force a layout update, call the setNeedsLayout() method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded() method.
Select the options for aligning the selected views, and click the Add Constraints button.
Every contraint has an attribute [constraint firstAttribute]
It returns an enum NSLayoutAttribute
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
NSLayoutAttributeLeft = 1,
NSLayoutAttributeRight,
NSLayoutAttributeTop,
NSLayoutAttributeBottom,
NSLayoutAttributeLeading,
NSLayoutAttributeTrailing,
NSLayoutAttributeWidth,
NSLayoutAttributeHeight,
NSLayoutAttributeCenterX,
NSLayoutAttributeCenterY,
NSLayoutAttributeBaseline,
NSLayoutAttributeNotAnAttribute = 0
};
so you can check NSLayoutAttributeWidth for width.
Sample code:
NSArray constraints = [self constraints];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstAttribute = %d", NSLayoutAttributeWidth];
NSArray *filteredArray = [constraints filteredArrayUsingPredicate:predicate];
if(filteredArray.count == 0){
return nil;
}
NSLayoutConstraint *constraint = [constraints objectAtIndex:0];
Here is the swift 3 version tested on Xcode 8.2.1 and macOS 10.12.2.
The code shows how to get a button's width and height constraints, but you could filter whatever you want from NSLayoutAttribute
enum.
let cons = signInButton.constraints.filter {
$0.firstAttribute == NSLayoutAttribute.width || $0.firstAttribute == NSLayoutAttribute.height /// or other from `NSLayoutAttribute`
}
// do something with the constraints array, e.g.
NSLayoutConstraint.deactivate(cons)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With