【发布时间】:2011-07-27 22:49:18
【问题描述】:
对于某些给定的固定宽度,我如何计算特定标签 (NSTextField) 中字符串的高度?
我搜索了各种方法并尝试了this method from Apple。它可以工作,除了对于较长的字符串来说,高度变得太短了。因此,目前的方法似乎存在一些不准确之处。
我在谷歌上搜索的其他代码也有同样的问题。
这里有人有任何准确代码来查找文本高度(给定特定宽度)吗?
【问题讨论】:
标签: objective-c macos cocoa
对于某些给定的固定宽度,我如何计算特定标签 (NSTextField) 中字符串的高度?
我搜索了各种方法并尝试了this method from Apple。它可以工作,除了对于较长的字符串来说,高度变得太短了。因此,目前的方法似乎存在一些不准确之处。
我在谷歌上搜索的其他代码也有同样的问题。
这里有人有任何准确代码来查找文本高度(给定特定宽度)吗?
【问题讨论】:
标签: objective-c macos cocoa
我使用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 的高度确实是准确的。
我可能省略了一些小细节,但你明白了。我希望这对那里的人有所帮助。
【讨论】:
[textView setFont:[NSFont systemFontOfSize:13] range:NSMakeRange(0,[someString length])]; 这是这里最重要的一行。如果没有它,如果界面构建器中的文本视图设置为相同的字体和大小,您将得到错误的高度甚至。我还必须在我的 tableview 中的每个 setString 之后写下这一行,否则事情会变得很时髦。
(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 个小时来解决一个看似简单的问题时,我总是觉得自己非常愚蠢。
轻微编辑:经过仔细检查,这只有在我要求单元格计算其高度之前阅读NSTextField 的stringValue 才有效。所以我在实际计算之前添加了以下 nonsensical 行:
[yourTextField setStringValue:yourTextField.stringValue];
我知道这真的很很糟糕,但现在我不在乎了。我只想要一个可靠的解决方案。随意对我投反对票或更好:建议更好的解决方案。
Swift 中的解决方案(感谢 iphaaw 让我注意到这一点!)
myTextField.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), width, CGFloat(FLT_MAX))).height
【讨论】:
cellforview 但没有用
非常感谢 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
【讨论】:
这是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
}
}
【讨论】:
看看NSString Application Kit Additions Reference。 – sizeWithAttributes: 或 – boundingRectWithSize:options:attributes: 似乎可以做你想做的事。
【讨论】:
Vigorouscoding 的回答效果很好!这真的很糟糕吗?它似乎工作得很好。最后在花了很多时间尝试其他解决方案之后。
这是我对代码的 Swift 翻译:
myTextField.cell!.cellSizeForBounds(NSMakeRect(CGFloat(0.0), CGFloat(0.0), width, CGFloat(FLT_MAX))).height
请不要投票给这个答案。转而为精力充沛的编码的条目投票。
【讨论】: