以编程方式自动布局
Posted
技术标签:
【中文标题】以编程方式自动布局【英文标题】:Autolayout programmatically 【发布时间】:2015-10-26 12:44:52 【问题描述】:我有点想深入了解自动布局。我对故事板中的自动布局有相当的了解。此外,我也知道如何使用 NSLayoutConstraint 类。 这是问题:我有 2 个视图(redView 和 yellowView)。从情节提要中,我已经设置了两个视图的约束。现在在我的代码中,假设我想改变 redView 的宽度 w.r.t 的宽度 yellowView.So我为此使用了以下代码:
NSLayoutConstraint *layouts1 = [NSLayoutConstraint
constraintWithItem:_redView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:_yellowView
attribute:NSLayoutAttributeWidth
multiplier:3.0f
constant:0];
[self.view addConstraint:layouts1];
现在我运行代码,虽然我得到了预期的输出,但它在控制台上显示“不可满足的约束”消息(它应该是因为正在设置多个宽度)。现在的问题是:我怎样才能摆脱它信息? 我已经尝试了几件事,但它们不起作用。这是我尝试过的:
-
我没有在情节提要中设置约束。而是直接使用以下代码。
我尝试使用“layoutIfNeeded”方法。
好吧,我可以以编程方式编写整个自动布局代码,但由于我们有权通过情节提要设置自动布局,因此完全没有必要。必须有某种方法以编程方式更新约束(在情节提要中设置)而不会产生任何冲突.
【问题讨论】:
如果你想将红色视图设置为黄色视图的等宽,那么你可以使用等宽作为静态。但是如果宽度发生变化,您需要将宽度约束连接到代码,您可以更改 d 常量值 但是如果我在设置相等的宽度之后再写上面的代码,我还是会遇到同样的问题。想想吧。 这是一个很好的帖子 - ios 9 中的锚样式是救命稻草***.com/questions/26180822/… 尝试使用砌体进行自动布局!!!! 当您想以编程方式编辑现有约束时,我是否理解正确? IE。故事板的约束集?您可以从约束中创建一个 IBOutlet,并以编程方式设置其常量属性。然后调用layotIfNeeded。 【参考方案1】:当您想以编程方式编辑现有约束时,我的理解是否正确? IE。故事板的约束集?
您可以从约束中创建一个IBOutlet
,并以编程方式设置其constant
-property。然后拨打layotIfNeeded
。
【讨论】:
【参考方案2】:嗯,我明白我想要做什么。因为我已经在情节提要中设置了约束,我需要删除该宽度约束(在情节提要中)以使用新约束对其进行更新。所以我刚刚创建了一个 IBOutlet我的黄色视图的宽度,然后这段代码对我有用:
[_yellowView removeConstraint:_myConstraints];//_myConstraints is the outlet
现在我没有遇到任何问题。非常感谢大家 :-)
【讨论】:
我已经回答了我的评论。如果您认为这是对您问题的回答,您可以接受。 @Spoek 解决此问题的另一种方法,因此我的知识库有所收获:-)【参考方案3】:MARK:- 查找约束
- (NSLayoutConstraint *)myConstraintWithAttribute:(NSLayoutAttribute)attribute
/* Find constraint with attribute in my constraints */
__block NSLayoutConstraint *resultConstraint;
[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop)
// DebugLog(@"constraint %@", constraint);
if ([NSStringFromClass([NSLayoutConstraint class]) isEqualToString:NSStringFromClass([constraint class])])
if (constraint.firstAttribute == attribute || constraint.secondAttribute == attribute)
resultConstraint = constraint;
*stop = YES;
];
return resultConstraint;
- (NSLayoutConstraint *)superviewConstraintWithAttribute:(NSLayoutAttribute)attribute
/* Find constraint with attribute in my superview's constraints */
__block NSLayoutConstraint *resultConstraint;
[self.superview.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop)
if (constraint.firstItem == self && constraint.firstAttribute == attribute)
//|| (constraint.secondItem == self && constraint.secondAttribute == attribute))
resultConstraint = constraint;
*stop = YES;
];
return resultConstraint;
- (NSLayoutConstraint *)constraintWithAttribute:(NSLayoutAttribute)attribute
/* Find constraint with attribute in my constraints */
NSLayoutConstraint *resultConstraint = [self myConstraintWithAttribute:attribute];
/* Find constraint with attribute in my superview's constraints */
if (!resultConstraint)
resultConstraint = [self superviewConstraintWithAttribute:attribute];
return resultConstraint;
- (BOOL)removeConstraintWithAttribute:(NSLayoutAttribute)attribute
NSLayoutConstraint *constraint = [self superviewConstraintWithAttribute:attribute];
if (constraint)
[self.superview removeConstraint:constraint];
return YES;
constraint = [self myConstraintWithAttribute:attribute];
if (constraint)
[self removeConstraint:constraint];
return YES;
return NO;
MARK:- 删除约束
- (void)removeMyConstraints
/* Remove all my constraitns from superview */
[self.superview removeConstraints:[self mySuperviewConstraints]];
/* Remove my constraitns */
[self removeConstraints:self.constraints];
- (NSArray *)mySuperviewConstraints
NSMutableArray *mySuperviewConstraints = [NSMutableArray array];
[self.superview.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop)
if (constraint.firstItem == self || constraint.secondItem == self)
[mySuperviewConstraints addObject:constraint];
];
return mySuperviewConstraints;
- (void)removeMyConstraintsButKeepMySubviewConstraints
/* Remove all my constraitns from superview */
[self.superview removeConstraints:[self mySuperviewConstraints]];
/* Remove my constraitns */
[self removeConstraints:[self myConstraints]];
- (NSArray *)myConstraints
NSMutableArray *myConstraints = [NSMutableArray array];
[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop)
if (constraint.firstItem == self && constraint.secondItem == nil)
[myConstraints addObject:constraint];
];
return myConstraints;
MARK:- 尺寸限制
- (void)addWidthConstraint:(CGFloat)width
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1
constant:width];
[self addConstraint:constraint];
- (void)addWidthConstraintFromLabel:(UILabel *)label
withOffset:(CGFloat)offset
NSDictionary *attributes = @NSFontAttributeName : label.font;
return [self addWidthConstraint:[label.text sizeWithAttributes:attributes].width + offset];
- (void)addHeightConstraint:(CGFloat)height
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1
constant:height];
[self addConstraint:constraint];
- (void)addMaximumHeightConstraint:(CGFloat)maxHeight
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:nil
attribute:0
multiplier:1
constant:maxHeight];
[self addConstraint:constraint];
- (void)addWidthConstraintFromImage:(UIImage *)image
[self addWidthConstraint:image.size.width];
- (void)addHeightConstraintFromImage:(UIImage *)image
[self addHeightConstraint:image.size.height];
MARK:- 中心约束
- (void)addCenterConstraint:(UIView *)view
centerDirection:(NSLayoutAttribute)centerDirection
offset:(CGFloat)offset
UIView *viewItem = (view) ? view : self.superview;
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self
attribute:centerDirection
relatedBy:NSLayoutRelationEqual
toItem:viewItem
attribute:centerDirection
multiplier:1
constant:offset];
[self.superview addConstraint:constraint];
- (void)addCenterXConstraint:(UIView *)view
[self addCenterConstraint:view
centerDirection:NSLayoutAttributeCenterX
offset:0];
- (void)addCenterYConstraint:(UIView *)view
[self addCenterConstraint:view
centerDirection:NSLayoutAttributeCenterY
offset:0];
- (void)addCenterXConstraint:(UIView *)view
offset:(CGFloat)offset
[self addCenterConstraint:view
centerDirection:NSLayoutAttributeCenterX
offset:offset];
- (void)addCenterYConstraint:(UIView *)view
offset:(CGFloat)offset
[self addCenterConstraint:view
centerDirection:NSLayoutAttributeCenterY
offset:offset];
MARK:- 边缘连接约束
- (void)addEdgeAttachConstraint:(UIView *)view
viewEdge:(NSLayoutAttribute)viewLayoutAttribute
offset:(CGFloat)offset
edge:(NSLayoutAttribute)layoutAttribute
UIView *viewItem = (view) ? view : self.superview;
/* Reverse offset for right side and bottom */
CGFloat fixedOffset = offset;
if (layoutAttribute == NSLayoutAttributeRight
|| layoutAttribute == NSLayoutAttributeBottom
|| layoutAttribute == NSLayoutAttributeTrailing)
fixedOffset = -offset;
/* Add contraint */
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self
attribute:layoutAttribute
relatedBy:NSLayoutRelationEqual
toItem:viewItem
attribute:viewLayoutAttribute
multiplier:1
constant:fixedOffset];
[self.superview addConstraint:constraint];
- (void)addLeftEdgeAttachConstraint:(UIView *)view
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:NSLayoutAttributeLeft
offset:offset
edge:NSLayoutAttributeLeft];
- (void)addRightEdgeAttachConstraint:(UIView *)view
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:NSLayoutAttributeRight
offset:offset
edge:NSLayoutAttributeRight];
- (void)addTopEdgeAttachConstraint:(UIView *)view
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:NSLayoutAttributeTop
offset:offset
edge:NSLayoutAttributeTop];
- (void)addBottomEdgeAttachConstraint:(UIView *)view
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:NSLayoutAttributeBottom
offset:offset
edge:NSLayoutAttributeBottom];
- (void)addLeftEdgeAttachConstraint:(UIView *)view
[self addLeftEdgeAttachConstraint:view
offset:0];
- (void)addRightEdgeAttachConstraint:(UIView *)view
[self addRightEdgeAttachConstraint:view
offset:0];
- (void)addTopEdgeAttachConstraint:(UIView *)view
[self addTopEdgeAttachConstraint:view
offset:0];
- (void)addBottomEdgeAttachConstraint:(UIView *)view
[self addBottomEdgeAttachConstraint:view
offset:0];
- (void)addEdgeAttachConstraints:(UIView *)view
leftOffset:(CGFloat)leftOffset
rightOffset:(CGFloat)rightOffset
topOffset:(CGFloat)topOffset
bottomOffset:(CGFloat)bottomOffset
[self addLeftEdgeAttachConstraint:view
offset:leftOffset];
[self addRightEdgeAttachConstraint:view
offset:rightOffset];
[self addTopEdgeAttachConstraint:view
offset:topOffset];
[self addBottomEdgeAttachConstraint:view
offset:bottomOffset];
- (void)addEdgeAttachConstraints:(UIView *)view
[self addLeftEdgeAttachConstraint:view];
[self addRightEdgeAttachConstraint:view];
[self addTopEdgeAttachConstraint:view];
[self addBottomEdgeAttachConstraint:view];
MARK: - 不同边缘的边缘约束
- (void)addLeftEdgeAttachConstraint:(UIView *)view
viewEdge:(NSLayoutAttribute)viewLayoutAttribute
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:viewLayoutAttribute
offset:offset
edge:NSLayoutAttributeLeft];
- (void)addRightEdgeAttachConstraint:(UIView *)view
viewEdge:(NSLayoutAttribute)viewLayoutAttribute
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:viewLayoutAttribute
offset:offset
edge:NSLayoutAttributeRight];
- (void)addTopEdgeAttachConstraint:(UIView *)view
viewEdge:(NSLayoutAttribute)viewLayoutAttribute
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:viewLayoutAttribute
offset:offset
edge:NSLayoutAttributeTop];
- (void)addBottomEdgeAttachConstraint:(UIView *)view
viewEdge:(NSLayoutAttribute)viewLayoutAttribute
offset:(CGFloat)offset
[self addEdgeAttachConstraint:view
viewEdge:viewLayoutAttribute
offset:offset
edge:NSLayoutAttributeBottom];
MARK:- 尺寸附加限制
- (void)addSizeAndSuperviewAttachConstraints:(NSString *)sizeConstraint
firstOffset:(CGFloat)firstOffset
secondOffset:(CGFloat)secondOffset
direction:(NSString *)direction
NSDictionary *viewDict = NSDictionaryOfVariableBindings(self);
NSString *visualFormatString;
if (sizeConstraint)
visualFormatString = [NSString stringWithFormat:@"%@:|-%f-[self(%@)]-%f-|", direction, firstOffset, sizeConstraint, secondOffset];
else
visualFormatString = [NSString stringWithFormat:@"%@:|-%f-[self]-%f-|", direction, firstOffset, secondOffset];
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:visualFormatString
options:0
metrics:0
views:viewDict];
[self.superview addConstraints:constraints];
- (void)addWidthAndSuperviewAttachConstraints:(NSString *)widthConstraint
leftOffset:(CGFloat)leftOffset
rightOffset:(CGFloat)rightOffset
[self addSizeAndSuperviewAttachConstraints:widthConstraint
firstOffset:leftOffset
secondOffset:rightOffset
direction:@"H"];
- (void)addHeightAndSuperviewAttachConstraints:(NSString *)heightConstraint
topOffset:(CGFloat)topOffset
bottomOffset:(CGFloat)bottomOffset
[self addSizeAndSuperviewAttachConstraints:heightConstraint
firstOffset:topOffset
secondOffset:bottomOffset
direction:@"V"];
MARK:- 行和列布局约束
- (void)addLayoutConstraintsForMySubviews:(NSArray *)views
firstOffset:(CGFloat)firstOffset
secondOffset:(CGFloat)secondOffset
betweenOffset:(NSString *)betweenOffset
direction:(NSString *)direction
equalSize:(BOOL)equalSize
/* Create viewDict and visualFormatString */
NSMutableString *visualFormatString = [[NSMutableString alloc] initWithFormat:@"%@:|-%.0f-", direction, firstOffset];
NSMutableDictionary *viewDict = [[NSMutableDictionary alloc] init];
[views enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop)
NSString *viewName = [NSString stringWithFormat:@"view%i", idx];
[viewDict setObject:view
forKey:viewName];
if (idx < [views count] - 1)
/* Add each view */
if (betweenOffset) /* Add offset between view */
/* Add equal size to prev view for all but index 0 */
if (equalSize && idx > 0)
NSString *prevViewName = [NSString stringWithFormat:@"view%i", idx - 1];
[visualFormatString appendFormat:@"[%@(==%@)]-%@-", viewName, prevViewName, betweenOffset];
else
[visualFormatString appendFormat:@"[%@]-%@-", viewName, betweenOffset];
else /* No offset between views */
/* Add equal size to prev view for all but index 0 */
if (equalSize && idx > 0)
NSString *prevViewName = [NSString stringWithFormat:@"view%i", idx - 1];
[visualFormatString appendFormat:@"[%@(==%@)]", viewName, prevViewName];
else
[visualFormatString appendFormat:@"[%@]", viewName];
else
/* Add equal size to prev view for all but index 0 */
if (equalSize && idx > 0)
NSString *prevViewName = [NSString stringWithFormat:@"view%i", idx - 1];
[visualFormatString appendFormat:@"[%@(==%@)]-%.0f-|", viewName, prevViewName, secondOffset];
else
[visualFormatString appendFormat:@"[%@]-%.0f-|", viewName, secondOffset];
];
// DebugLog(@"viewDict %@", viewDict);
// DebugLog(@"visualFormatString %@", visualFormatString);
/* Add constraints */
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:visualFormatString
options:0
metrics:0
views:viewDict];
[self addConstraints:constraints];
- (void)addRowLayoutConstraintsForMySubviews:(NSArray *)subviews
leftOffset:(CGFloat)leftOffset
rightOffset:(CGFloat)rightOffset
betweenOffset:(NSString *)betweenOffset
equalWidth:(BOOL)equalWidth
[self addLayoutConstraintsForMySubviews:subviews
firstOffset:leftOffset
secondOffset:rightOffset
betweenOffset:betweenOffset
direction:@"H"
equalSize:equalWidth];
- (void)addColumnLayoutConstraintsForMySubviews:(NSArray *)subviews
topOffset:(CGFloat)topOffset
bottomOffset:(CGFloat)bottomOffset
betweenOffset:(NSString *)betweenOffset
equalHeight:(BOOL)equalHeight
[self addLayoutConstraintsForMySubviews:subviews
firstOffset:topOffset
secondOffset:bottomOffset
betweenOffset:betweenOffset
direction:@"V"
equalSize:equalHeight];
MARK:- 行列等大小布局约束
- (void)addEqualSizeLayoutConstraintsForMySubviews:(NSArray *)views
firstOffset:(CGFloat)firstOffset
secondOffset:(CGFloat)secondOffset
betweenOffset:(NSString *)betweenOffset
direction:(NSString *)direction
/* Create viewDict and visualFormatString */
NSMutableString *visualFormatString = [[NSMutableString alloc] initWithFormat:@"%@:|-%.0f-", direction, firstOffset];
NSMutableDictionary *viewDict = [[NSMutableDictionary alloc] init];
[views enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop)
NSString *viewName = [NSString stringWithFormat:@"view%i", idx];
[viewDict setObject:view
forKey:viewName];
if (idx < [views count] - 1)
if (betweenOffset)
[visualFormatString appendFormat:@"[%@]-%@-", viewName, betweenOffset];
else
[visualFormatString appendFormat:@"[%@(>=40)]", viewName];
else
[visualFormatString appendFormat:@"[%@(>=40)]-%.0f-|", viewName, secondOffset];
];
// DebugLog(@"viewDict %@", viewDict);
/* Add constraints */
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[view0]-2-[view1(==view0)]-2-[view2(==view1)]-2-[view3(==view2)]-2-[view4(==view3)]-2-[view5(==view4)]-0-|"
options:0
metrics:0
views:viewDict];
[self addConstraints:constraints];
- (void)addRowLayoutEqualWidthConstraintsForMySubviews:(NSArray *)subviews
leftOffset:(CGFloat)leftOffset
rightOffset:(CGFloat)rightOffset
betweenOffset:(NSString *)betweenOffset
[self addEqualSizeLayoutConstraintsForMySubviews:subviews
firstOffset:leftOffset
secondOffset:rightOffset
betweenOffset:betweenOffset
direction:@"H"];
【讨论】:
以上是关于以编程方式自动布局的主要内容,如果未能解决你的问题,请参考以下文章