计算文本容器的高度

问题描述:

为了显示NSTableView中的视图,我必须计算NSTextField中的文本。我用这个方法:计算文本容器的高度

float heightForStringDrawing(NSString *myString, NSFont *myFont,float myWidth) { 
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:myString]; 
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(myWidth, FLT_MAX)]; 
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; 
    [layoutManager addTextContainer:textContainer]; 
    [textStorage addLayoutManager:layoutManager]; 
    [textStorage addAttribute:NSFontAttributeName value:myFont 
         range:NSMakeRange(0, [textStorage length])]; 


    (void) [layoutManager glyphRangeForTextContainer:textContainer]; 
    return [layoutManager usedRectForTextContainer:textContainer].size.height; 
} 

在线路的衬纸它的作品不错,但是当我有一个以上的线我的看法高度的精确宽度太小。我一直在寻找答案几个小时,但我仍然没有任何东西。下面是截图:

enter image description here

我加入十,因为填充的函数的结果。正如你可以看到短信一样,它可以很好地工作,而且它的裁剪时间越长。感谢您的帮助。

您没有显示调用heightForStringDrawing()函数的代码。你提供的宽度是多少?如果它是文本字段的宽度,那就错了,因为文本字段内的文本不允许一直走到文本字段的边缘。还有水平填充。

无论如何,有一个更直接的方法。创建一个与您要测量的属性相匹配的文本字段。设置其stringValuefont。将其preferredMaxLayoutWidth设置为可用宽度。 (请注意,这是根据对齐矩阵而不是帧矩形,如果需要转换,请使用-alignmentRectForFrame:。)现在,请询问它的intrinsicSize。然后您必须使用-frameForAlignmentRect:将其从对齐矩形转换为帧矩形。

根据您的情况,您可以通过存档和取消存档来复制现有文本字段,也可以加载包含它的NIB来获取它。以获得具有所需特性的文本字段


的方法之一是克隆现有之一:

NSData* data = [NSKeyedArchiver archivedDataWithRootObject:_label]; 
NSTextField* clone = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

为了计算所需要的帧的高度,以适应在给定的宽度:

NSRect rect = { NSZeroPoint, NSMakeSize(desiredWidth, 100 /* arbitrary */) }; 
rect = [clone alignmentRectForFrame:rect]; 
clone.preferredMaxLayoutWidth = NSWidth(rect); 
rect.size = clone.intrinsicContentSize; 
rect = [clone frameForAlignmentRect:rect]; 
CGFloat resultingHeight = NSHeight(rect); 

现在,在您的屏幕截图中,行高必须高于文本字段高度,因为那里有空白。高了多少取决于你的布局。由于您在评论中提到了约束条件,因此您大概会使用自动布局。在这种情况下,边距(约束距离)实际上将应用于文本字段的对齐矩形。所以,你会跳过第二行到最后一行代码。也就是说,行高将是文本字段的固有高度(未调整)加上约束施加的边距。

为了避免大量使用边距来处理这些事情,您应该使用与您的表格单元格视图匹配的完整视图层次结构。所以,你直接加载你的表格单元格视图NIB。您可以根据需要设置文本字段的内容(以及您的单元格视图的子视图所需的任何其他内容)。您将宽度约束应用于单元格视图本身以模拟列宽。然后,你会问细胞视图的fittingSize。让自动布局系统根据内容计算整体高度,包括边界和约束所隐含的所有内容。

当然,这只适用于文本字段正在使用preferredMaxLayoutWidth。否则,它不会响应包装而增加其内在高度。由于您不想对首选宽度或边距大小进行硬编码,因此您可以执行两遍。在单元格视图内设置控件的内容并添加宽度约束后,请致电-layoutSubtreeIfNeeded。然后,查询文本字段的帧,将其转换为对齐矩形,将preferredMaxLayoutWidth设置为对齐宽度,然后仅查询单元视图的fittingSize。我

+0

'的NSString * s = @ “过长的字符串值,将它放入评论”;' 'NSFont *字体= [NSFont fontWithName:@ “Helvetica Neue字体”大小:13];' 'h = heightForStringDrawing(s,font,100-4);' 这就是我如何调用这个方法。 100 - 圆形绿色自定义视图的宽度。 -4由于customView - textfield(2两侧)的限制。我已经尝试过你的方法,但它不起作用。它返回的高度要求更低。 – PawelPawel

+0

我更新了我的答案。我忘记了要注意的是,您必须将对齐矩形的内在高度转换为框架矩形。 –

+0

@Ąowski,我用示例代码再次更新了我的答案。我还描述了一种使用全单元格视图的方法,因为它很容易在代码中重现您的约束边界。 –

工作完美的解决方案:

// creating temporary cell just to take height from it later 
NSTextFieldCell *tmp = [NSTextFieldCell new]; 
// settings proper values from out NSTextField which we want to check height for 
[tmp setStringValue:s]; 
[tmp setFont:font]; 
NSRect rect; 
rect.size.height=FLT_MAX; 
// width which we want to check height for 
// in my case 100 (width of nstextfield), -4 (minus left and right margin) 
rect.size.width=100-4; 
// getting needed height 
h = [tmp cellSizeForBounds:rect].height; 
+0

这会获得单元格大小的权利,但不会保留它的文本字段的大小。它忽略了文本字段使用的边界周围的一些边界。 –

+0

那么以某种方式将它放入'NSTextField'中,然后取大小呢?我试过你在上面发布的内容,但它不起作用,或者我不明白。 – PawelPawel