Search code examples
ios6autolayoutnslayoutconstraint

Why is NSLayoutAttributeCenterX an 'Invalid pairing' with NSLayoutAttributeWidth


I am trying to have the auto layout manager adjust the center point of a view, based on the width of the super view. I don't understand why that is an 'Invalid Pairing' of the attributes (as told by the crash and NSInvalidArgumentException)

UIView *ac;
NSLayoutConstraint *cXloc = [NSLayoutConstraint constraintWithItem:ac 
                                                         attribute:NSLayoutAttributeCenterX 
                                                         relatedBy:NSLayoutRelationEqual 
                                                            toItem:ac.superview 
                                                         attribute:NSLayoutAttributeWidth 
                                                        multiplier:.1 
                                                          constant:x*ac.superview.frame.size.width*.2];
[ac.superview addConstraint:cXloc];

Could someone explain why this is an 'Invalid paring' and how I should approach this? Thanks


Solution

  • If you relate ac's AttributeCenterX to its superview's AttributeCenterX, AttributeLeading, or AttributeTrailing, you should be able to express your desired constraint using the multiplier and constraint. Keep in mind that the constant is evaluated only when the constraint is created, and your example's constant wouldn't update as ac.superview's width changes.

    If you can express in words how you'd like ac positioned relative to its superview, we can suggest a constraint.

    Edit

    Here's an example with 5 NSButtons. They themselves and the space between them expand so that the spaces are 30% as wide as the buttons, all the buttons have the same width, and all the spaces have the same width. Creating 4 invisible NSViews just for spacing is pretty cumbersome, especially considering you've got it working outside of autolayout. But in case you're curious:

    // Assuming these NSViews and NSButtons exist,
    //NSView* superview ;
    //NSButton *buttonOne, *buttonTwo, *buttonThree, *buttonFour, *buttonFive ;
    
    
    [superView removeConstraints:superView.constraints] ;
    
    // Create empty NSViews to fill the space between the 5 buttons.
    NSView* spaceOne = [NSView new] ;
    NSView* spaceTwo = [NSView new] ;
    NSView* spaceThree = [NSView new] ;
    NSView* spaceFour = [NSView new] ;
    spaceOne.translatesAutoresizingMaskIntoConstraints = NO ;
    spaceTwo.translatesAutoresizingMaskIntoConstraints = NO ;
    spaceThree.translatesAutoresizingMaskIntoConstraints = NO ;
    spaceFour.translatesAutoresizingMaskIntoConstraints = NO ;
    [superView addSubview:spaceOne] ;
    [superView addSubview:spaceTwo] ;
    [superView addSubview:spaceThree] ;
    [superView addSubview:spaceFour] ;
    
    NSDictionary* views = NSDictionaryOfVariableBindings(superView,buttonOne,buttonTwo,buttonThree,buttonFour,buttonFive,spaceOne,spaceTwo,spaceThree,spaceFour) ;
    
    // Vertically align buttonOne to its superview however you like.
    [superView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonOne]"  options:0  metrics:nil  views:views ] ] ;
    
    // Make the "space" NSViews' widths equal and >= 10. Make the buttons' widths equal.
    [superView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[buttonOne][spaceOne(>=10)][buttonTwo(==buttonOne)][spaceTwo(==spaceOne)][buttonThree(==buttonOne)][spaceThree(==spaceOne)][buttonFour(==buttonOne)][spaceFour(==spaceOne)][buttonFive(==buttonOne)]|"  options: NSLayoutFormatAlignAllCenterY  metrics:nil  views:views ] ] ;
    // Make the "space" NSViews' widths 30% of the NSButtons' widths.
    [superView addConstraint: [NSLayoutConstraint constraintWithItem: spaceOne
                                                           attribute: NSLayoutAttributeWidth
                                                           relatedBy: NSLayoutRelationEqual
                                                              toItem: buttonOne
                                                           attribute: NSLayoutAttributeWidth
                                                          multiplier: 0.3
                                                            constant: 0 ] ] ;