【问题标题】:How to let NSTextField grow with the text in auto layout?如何让 NSTextField 与自动布局中的文本一起增长?
【发布时间】:2012-05-05 16:15:10
【问题描述】:

Lion 中的自动布局应该让文本字段(以及标签)随着它所包含的文本一起增长变得相当简单。

文本字段设置为在 Interface Builder 中换行。

有什么简单可靠的方法来做到这一点?

【问题讨论】:

    标签: cocoa nstextfield autolayout


    【解决方案1】:

    NSView 中的 intrinsicContentSize 方法返回视图本身认为的固有内容大小。

    NSTextField 计算此值时不考虑其单元格的 wraps 属性,因此它会报告文本在单行中的尺寸。

    因此,NSTextField 的自定义子类可以覆盖此方法以返回更好的值,例如单元格的 cellSizeForBounds: 方法提供的值:

    -(NSSize)intrinsicContentSize
    {
        if ( ![self.cell wraps] ) {
            return [super intrinsicContentSize];
        }
    
        NSRect frame = [self frame];
    
        CGFloat width = frame.size.width;
    
        // Make the frame very high, while keeping the width
        frame.size.height = CGFLOAT_MAX;
    
        // Calculate new height within the frame
        // with practically infinite height.
        CGFloat height = [self.cell cellSizeForBounds: frame].height;
    
        return NSMakeSize(width, height);
    }
    
    // you need to invalidate the layout on text change, else it wouldn't grow by changing the text
    - (void)textDidChange:(NSNotification *)notification
    {
        [super textDidChange:notification];
        [self invalidateIntrinsicContentSize];
    }
    

    【讨论】:

    • 这完全符合我所看到的。澄清一下,忽略单元格上的 'wraps' 属性似乎是 Lion 中的一个错误,已在 Mountain Lion 中修复。因此,如果您的目标是 Lion 及以上,您将在 2 个操作系统中看到不同的结果,直到您应用错误修复以使 Lion 加速。
    • 是的,这是 Lion 中的一个错误。我真的希望 Apple 能够在 OS X 10.7 && 10.8 中解决这些问题。在我的实现中,我对特殊情况进行了更多检查(例如,如果它是 Lion || 如果语言不是英语)并且我将我的身高设置得有点不同。尽管如此,Monolo 发布的内容是一个好的开始。
    • IntrinsicContentSize: 方法在通过 setStringValue: 更改文本时不会被调用。
    • 你需要使布局无效 - (void)textDidChange:(NSNotification *)notification { [super textDidChange:notification]; [自我无效内在内容大小]; }
    • 最近有没有人制作过这个的 Swift 版本?
    【解决方案2】:

    斯威夫特 4

    可编辑的自动调整 NSTextField

    基于 Peter Lapisu 的 Objective-C 帖子

    子类NSTextField,在下面添加代码。

    override var intrinsicContentSize: NSSize {
        // Guard the cell exists and wraps
        guard let cell = self.cell, cell.wraps else {return super.intrinsicContentSize}
    
        // Use intrinsic width to jive with autolayout
        let width = super.intrinsicContentSize.width
    
        // Set the frame height to a reasonable number
        self.frame.size.height = 750.0
    
        // Calcuate height
        let height = cell.cellSize(forBounds: self.frame).height
    
        return NSMakeSize(width, height);
    }
    
    override func textDidChange(_ notification: Notification) {
        super.textDidChange(notification)
        super.invalidateIntrinsicContentSize()
    }
    

    self.frame.size.height 设置为“合理的数字”避免在使用FLT_MAXCGFloat.greatestFiniteMagnitude 或大数字时出现一些错误。当用户选择突出显示字段中的文本时,会在操作过程中出现错误,他们可以将滚动向上和向下拖动到无穷大。此外,当用户输入文本时,NSTextField 会被置空,直到用户结束编辑。最后,如果用户选择了NSTextField,然后尝试调整窗口大小,如果self.frame.size.height 的值太大,窗口就会挂起。

    【讨论】:

      【解决方案3】:

      接受的答案是基于对intrinsicContentSize 的操作,但并非在所有情况下都需要这样做。如果 (a) 你给文本域一个preferredMaxLayoutWidth 和 (b) 使这个域不是editable,自动布局会增加和缩小文本域的高度。这些步骤使文本字段能够确定其固有宽度并计算自动布局所需的高度。有关详细信息,请参阅 this answerthis answer

      更模糊的是,如果您在字段上使用绑定并且未能清除 Conditionally Sets Editable 选项,则自动布局将中断对文本字段的 editable 属性的依赖性。

      【讨论】:

      • 完美。谢谢你。正是这些小事导致从 iOS 迁移到 Mac 令人沮丧。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-04
      • 2020-09-07
      • 1970-01-01
      • 2017-11-04
      相关资源
      最近更新 更多