【问题标题】:*Accurately* calculating text height in Cocoa (for Mac, not iOS)*准确*在 Cocoa 中计算文本高度(适用于 Mac,而不是 iOS)
【发布时间】:2011-07-27 22:49:18
【问题描述】:

对于某些给定的固定宽度,我如何计算特定标签 (NSTextField) 中字符串的高度?

我搜索了各种方法并尝试了this method from Apple。它可以工作,除了对于较长的字符串来说,高度变得太短了。因此,目前的方法似乎存在一些不准确之处。

我在谷歌上搜索的其他代码也有同样的问题。

这里有人有任何准确代码来查找文本高度(给定特定宽度)吗?

【问题讨论】:

    标签: objective-c macos cocoa


    【解决方案1】:

    我使用http://www.sheepsystems.com/sourceCode/sourceStringGeometrics.html 提供的 NS(Attributed)String+Geometrics 类别解决了这个问题。在该类别的头文件中很好地解释了这些事情是如何工作的。具体来说,他们提到应该使用 NSTextView 而不是 NSTextField,因为后者几乎不可能获得准确的高度。

    因此,我用 NSTextView 替换了我的 NSTextField。首先,我使用以下代码使我的 NSTextView 看起来像我的 NSTextField:

    [textView setEditable:YES];
    [textView insertText:someString];
    [textView setFont:[NSFont fontWithName:@"Lucida Grande"
       size:11] range:NSMakeRange(0,[someString length])];
    [textView setEditable:NO];
    [textView setSelectable:NO];
    

    然后我用这段代码得到了高度:

    NSDictionary *attributes
      = [NSDictionary dictionaryWithObjectsAndKeys:
         [textView font],NSFontAttributeName,nil];
    NSAttributedString *attributedString
      = [[NSAttributedString alloc] initWithString:
         [textView string] attributes:attributes];
    CGFloat height = [attributedString heightForWidth:
                     [textView frame].size.width];
    

    NSTextView 的高度确实是准确的。

    我可能省略了一些小细节,但你明白了。我希望这对那里的人有所帮助。

    【讨论】:

    • 出色的工作解决了您自己的问题。这看起来也是有用的信息。请不要忘记接受其中一个答案,以免问题显示为“未回答”。
    • 是的,我会这样做的。但是我必须在发帖后等待 2 天(从现在起 22 小时)才能这样做。
    • [textView setFont:[NSFont systemFontOfSize:13] range:NSMakeRange(0,[someString length])]; 这是这里最重要的一行。如果没有它,如果界面构建器中的文本视图设置为相同的字体和大小,您将得到错误的高度甚至。我还必须在我的 tableview 中的每个 setString 之后写下这一行,否则事情会变得很时髦。
    • @Segev 太棒了,谢谢!我仍然会得到奇怪的高度值(实际文本大小的两倍)。我尝试了您设置标签字体的方法 after 设置文本字符串,并且效果很好。我猜 Xcode/macOS 中的奇怪错误...:/
    【解决方案2】:

    (Swift 中的解决方案在文末)

    我尝试了所有这些方法,但没有一个对我有用。对于我的NSTextField,“官方”方式(如 OP 所述)大部分时间都已关闭。切换到NSTextView 是不可能的,因为在添加“NSScrollView 中的 NSTextView”后 XCode/IB总是崩溃。

    长话短说,我找到了一种简单的方法来确定我的NSTextField 的高度,但这可以很容易地适应宽度。

    CGFloat minHeight = [((NSTextFieldCell *)[yourTextField cell]) cellSizeForBounds:NSMakeRect(0, 0, YOUR_MAX_WIDTH, FLT_MAX)].height;
    

    此代码适用于使用其他方法失败的每个测试用例。我希望这可以帮助别人。当我花 2 个小时来解决一个看似简单的问题时,我总是觉得自己非常愚蠢。

    轻微编辑:经过仔细检查,这只有在我要求单元格计算其高度之前阅读NSTextFieldstringValue 才有效。所以我在实际计算之前添加了以下 nonsensical 行:

    [yourTextField setStringValue:yourTextField.stringValue];
    

    我知道这真的很很糟糕,但现在我不在乎了。我只想要一个可靠的解决方案。随意对我投反对票或更好:建议更好的解决方案。


    Swift 中的解决方案(感谢 iphaaw 让我注意到这一点!)

    myTextField.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), width, CGFloat(FLT_MAX))).height
    

    【讨论】:

    • 感谢这个简单的解决方案。但为什么是演员?没有就完全没问题。对我来说,它没有“荒谬”的行。
    • vigorouscoding 我应该把这段代码放在哪里工作?我把它放在cellforview 但没有用
    【解决方案3】:

    非常感谢 iphaaw 和 Enchilada 提供了这个非常酷的小解决方案。我发现它在设置行高等方面效果很好,因此我将 iphaaw 的 Swift 转换为几个 NSTextField 扩展。享受

    extension NSTextField {
    func bestheight(text: String, width: CGFloat) -> CGFloat {
    
        self.stringValue = text
        let getnumber = self.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), width, CGFloat(FLT_MAX))).height
    
        return getnumber
       }
    }
    
    extension NSTextField {
    func bestwidth(text: String, height: CGFloat) -> CGFloat {
    
        self.stringValue = text
        let getnumber = self.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), CGFloat(FLT_MAX), height)).width
    
        return getnumber
       }
    }
    

    我希望有人觉得这些有用。关于KGH

    【讨论】:

      【解决方案4】:

      这是ArtbyKGH's answer Swift 4+:

      extension NSTextField {
          func bestHeight(for text: String, width: CGFloat) -> CGFloat {
              stringValue = text
              let height = cell!.cellSize(forBounds: NSRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude)).height
      
              return height
          }
      
          func bestWidth(for text: String, height: CGFloat) -> CGFloat {
              stringValue = text
              let width = cell!.cellSize(forBounds: NSRect(x: 0, y: 0, width: .greatestFiniteMagnitude, height: height)).width
      
              return width
          }
      }
      

      【讨论】:

        【解决方案5】:

        看看NSString Application Kit Additions Reference– sizeWithAttributes: – boundingRectWithSize:options:attributes: 似乎可以做你想做的事。

        【讨论】:

          【解决方案6】:

          Vigorouscoding 的回答效果很好!这真的很糟糕吗?它似乎工作得很好。最后在花了很多时间尝试其他解决方案之后。

          这是我对代码的 Swift 翻译:

          myTextField.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), width, CGFloat(FLT_MAX))).height
          

          请不要投票给这个答案。转而为精力充沛的编码的条目投票。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-02-13
            • 1970-01-01
            • 2013-01-28
            • 1970-01-01
            • 2016-05-27
            • 1970-01-01
            • 2020-12-11
            • 1970-01-01
            相关资源
            最近更新 更多