Search code examples
cocoaautolayoutxcode6nstextfieldnslayoutconstraint

NSTextField And AutoLayout: Autogrow height -> Programmatically


If I create a label in interface builder and set a string through code that does not fit its current size, the label will grow vertically to fit its size, great!. Besides the x & y constraint, Xcode creates a NSContentSizeLayoutConstraint that contains hugging and compression resistance.

Here is a log output of the constraint

<NSContentSizeLayoutConstraint:0x6080000a11a0 V:[NSTextField:0x600000180c30(17)] Hug:750 CompressionResistance:750>

The question is, how to do this programmatically? I have not found a way yet. There is no way to create a NSContentSizeLayoutConstraint and setting the contentCompressionResistance of the NSTextField does not seem to have any effect.

Here is my code:

 self.label = [[NSTextField alloc]initWithFrame:NSMakeRect(0, 0, 100, 20)];
[self.label setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.label setBordered:YES];
[[self.label cell] setLineBreakMode:NSLineBreakByWordWrapping];
[self.window.contentView addSubview:self.label];
 self.label.stringValue = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

NSDictionary *dict = @{@"label" : self.label};
[self.label.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label]"options:0 metrics:nil views:dict]];
[self.label.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label]" options:0 metrics:nil views:dict]];

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0 constant:40];
constraint.priority = 1;
[self.label addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0 constant:18];
constraint.priority = 1;
[self.label addConstraint:constraint];

[self.label setContentCompressionResistancePriority:1000 forOrientation:NSLayoutConstraintOrientationHorizontal];
[self.label setContentCompressionResistancePriority:1000 forOrientation:NSLayoutConstraintOrientationVertical];

Solution

  • Set the text field's preferredMaxLayoutWidth. I think you then don't want or need the explicit width constraint.


    In my testing, I find that this works:

    self.label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)];
    self.label.translatesAutoresizingMaskIntoConstraints = NO;
    [self.label.cell setLineBreakMode:NSLineBreakByWordWrapping];
    self.label.stringValue = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
    self.label.preferredMaxLayoutWidth = 100;
    self.label.editable = NO;
    
    [self.window.contentView addSubview:self.label];
    
    NSDictionary* views = @{ @"label" : self.label };
    [self.label.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label]" options:0 metrics:nil views:views]];
    [self.label.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label]" options:0 metrics:nil views:views]];
    

    Basically, the main difference from yours is that I set editable to NO. I also leave out the width and height constraints and setting the compression resistance.