NSTextField 和 AutoLayout:自动增长高度 -> 以编程方式

Posted

技术标签:

【中文标题】NSTextField 和 AutoLayout:自动增长高度 -> 以编程方式【英文标题】:NSTextField And AutoLayout: Autogrow height -> Programmatically 【发布时间】:2014-09-19 04:30:17 【问题描述】:

如果我在界面生成器中创建一个标签并通过不适合其当前大小的代码设置一个字符串,则标签将垂直增长以适应其大小,太棒了! 除了 x & y 约束,Xcode 创建一个 NSContentSizeLayoutConstraint 包含拥抱和压缩阻力。

这是约束的日志输出

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

问题是,如何以编程方式执行此操作?我还没有找到方法。没有办法创建 NSContentSizeLayoutConstraint 并且设置 NSTextField 的 contentCompressionResistance 似乎没有任何效果。

这是我的代码:

 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。我还省略了宽度和高度限制并设置了抗压性。

【讨论】:

感谢您的想法,但在设置 prefferedMaxLayoutWidth 且未设置宽度约束时,我收到一条布局不明确的消息。我也同时尝试过它们,但抗压性没有得到尊重。 试试[self.label setScrollable:NO]。如果这不起作用,我建议您创建您所说的在 IB 中有效的设置,然后检查文本字段及其单元格的所有相关属性并确保您的匹配。确保不仅要查询NSTextFieldNSTextFieldCell 中声明的属性,还要查询它们的超类。此外,让 IB 在文本字段上添加缺失或建议的约束。我怀疑你会发现它既没有高度也没有宽度限制,并且允许来自文本字段的固有大小。 就是这样,我不知道IB是如何添加这个“NSContentSizeLayoutConstraint”的。它是一个私人课程。我向 Apple 提出了技术支持请求,我会在得到答复后更新问题。 我说的是文本字段及其单元格的属性,而不是约束。我怀疑约束是由IB“添加”的。如果有的话,那是文本字段属性的结果。 谢谢。正如你告诉我的那样,可编辑属性会影响其布局约束。【参考方案2】:

我认为更好的方法是覆盖 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 
         validateEditing()
         invalidateIntrinsicContentSize()
      
   

之后约束按预期工作。请注意,它仅在您在 Interface Builder 或代码中将 Layout 设置为 Wraps 时才有效。

【讨论】:

这适用于初始布局,当我扩大窗口时会展开,但当我缩小窗口时不会换行。

以上是关于NSTextField 和 AutoLayout:自动增长高度 -> 以编程方式的主要内容,如果未能解决你的问题,请参考以下文章

NSTextField:公开其复制和粘贴方法

根据 Font/Size 改变 NSTextField 的高度

将 NSTextField 绑定到 NSString

NSTextfield + NSMenu 和第一响应者

NSTextField(标签)属性文本:选择

如何制作字幕 UILabel / UITextField / NSTextField