【问题标题】: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]; 

现在我运行代码,虽然我得到了预期的输出,但它在控制台上显示“不可满足的约束”消息(它应该是因为正在设置多个宽度)。现在的问题是:我怎样才能摆脱它信息? 我已经尝试了几件事,但它们不起作用。这是我尝试过的:

  1. 我没有在情节提要中设置约束。而是直接使用以下代码。
  2. 我尝试使用“layoutIfNeeded”方法。

好吧,我可以以编程方式编写整个自动布局代码,但由于我们有权通过情节提要设置自动布局,因此完全没有必要。必须有某种方法以编程方式更新约束(在情节提要中设置)而不会产生任何冲突.

【问题讨论】:

  • 如果你想将红色视图设置为黄色视图的等宽,那么你可以使用等宽作为静态。但是如果宽度发生变化,您需要将宽度约束连接到代码,您可以更改 d 常量值
  • 但是如果我在设置相等的宽度之后再写上面的代码,我还是会遇到同样的问题。想想吧。
  • 这是一个很好的帖子 - iOS 9 中的锚样式是救命稻草stackoverflow.com/questions/26180822/…
  • 尝试使用砌体进行自动布局!!!!
  • 当您想以编程方式编辑现有约束时,我是否理解正确? IE。故事板的约束集?您可以从约束中创建一个 IBOutlet,并以编程方式设置其常量属性。然后调用layotIfNeeded。

标签: ios autolayout


【解决方案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"];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-16
      • 2015-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多