*准确*计算 Cocoa 中的文本高度(适用于 Mac,不适用于 iOS)

问题描述 投票:0回答:6

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

我用谷歌搜索了各种方法并尝试了Apple 的这个方法。它可以工作,只是高度对于较长的字符串来说太短了一行。因此,目前的方法似乎存在一些不准确之处。

我在 Google 上搜索到的其他一些代码也遇到了同样的问题。

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

objective-c macos cocoa
6个回答
19
投票

我使用 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 的高度确实是准确的。

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


8
投票

(Swift 中的解决方案位于帖子末尾)

我尝试了所有这些方法,但没有一个对我有用。对于我的

NSTextField
来说,“官方”方式(正如OP提到的)大部分时间都是关闭的。切换到
NSTextView
是不可能的,因为 XCode/IB always 在添加“NSScrollView 中的 NSTextView”后崩溃。

长话短说,我发现了这种简单的方法来确定我的

NSTextField
的高度,但这可以很容易地适应宽度。

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

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

轻微编辑:经过仔细检查,只有在我要求单元格计算其高度之前阅读

stringValue
NSTextField
才有效。所以我在实际计算之前添加了以下无意义行:

[yourTextField setStringValue:yourTextField.stringValue];

我知道这真的很糟糕,但现在我不再关心了。我只是想要一个可靠的解决方案。请随意对我投反对票或更好:提出更好的解决方案。


Swift 中的解决方案

(感谢 iphaaw 让我注意到这一点!) myTextField.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), width, CGFloat(FLT_MAX))).height



5
投票

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(Float.greatestFiniteMagnitude))).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(Float.greatestFiniteMagnitude), height)).width return getnumber } }

我希望有人觉得这些有帮助。问候KGH


4
投票
ArtbyKGH 对 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 } }



2
投票
NSString 应用程序工具包添加参考

。看起来 – sizeWithAttributes:

 – boundingRectWithSize:options:attributes:
可以做你想做的事。
    


0
投票

这是我对代码的 Swift 翻译:

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

请不要对此答案进行投票。相反,请支持有活力编码的条目。

© www.soinside.com 2019 - 2024. All rights reserved.