NSTextField и AutoLayout: высота Autogrow -> программно

Если я создаю метку в конструкторе интерфейса и задаю строку в коде, который не соответствует ее текущему размеру, метка будет расти вертикально, чтобы соответствовать ее размеру, отлично! Помимо ограничения x & y, Xcode создает NSContentSizeLayoutConstraint, который содержит сопротивление объятиям и сжатию.

Вот вывод журнала ограничения

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

Вопрос в том, как это сделать программно? Я еще не нашел способ. Нет никакого способа создать NSContentSizeLayoutConstraint, и установка contentCompressionResistance NSTextField, кажется, не имеет никакого эффекта.

Вот мой код:

 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];

1 ответ

Решение

Установите текстовое поле preferredMaxLayoutWidth, Я думаю, что тогда вы не хотите или не нуждаетесь в явном ограничении ширины.


В моем тестировании я обнаружил, что это работает:

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]];

В основном, главное отличие от вашего в том, что я установил editable в NO, Я также опускаю ограничения ширины и высоты и устанавливаю сопротивление сжатию.

Я думаю, что лучший способ сделать это - переопределить NSTextField и обновить intrinsicContentSize.

public class DynamicTextField: NSTextField {
   public override var intrinsicContentSize: NSSize {
      if cell!.wraps {
         let fictionalBounds = NSRect(x: bounds.minX, y: bounds.minY, width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
         return cell!.cellSize(forBounds: fictionalBounds)
      } else {
         return super.intrinsicContentSize
      }
   }

   public override func textDidChange(_ notification: Notification) {
      super.textDidChange(notification)

      if cell!.wraps {
         validatingEditing()
         invalidateIntrinsicContentSize()
      }
   }
}

После этого ограничения работают как ожидалось. Обратите внимание, что это работает только при установке Layout в Wraps в Интерфейсном Разработчике или коде.

Другие вопросы по тегам