【问题标题】:NSString boundingRectWithSize slightly underestimating the correct height - why?NSString boundingRectWithSize 稍微低估了正确的高度 - 为什么?
【发布时间】:2012-08-23 04:30:17
【问题描述】:

我正在尝试根据当前宽度自动调整文本字段/视图的大小。换句话说,我希望宽度保持不变,但根据提供给它的文本调整高度。

它似乎正在工作,但由于某种原因,它与我的窗口底部对齐,尽管努力手动将其移回。谁能看到我在这里做错了什么?

NSString *temp = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel felis nec massa ultricies blandit non id arcu. Sed enim est, facilisis a feugiat in, consectetur eget arcu. Aenean rutrum, lacus id euismod congue, nisl erat vulputate lectus, non faucibus tortor purus sed sem. Donec tempor dui egestas velit auctor vitae faucibus diam facilisis. Morbi convallis nulla quis est pulvinar quis ultricies sem sollicitudin.";

myText.stringValue = temp;

NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                            [NSFont systemFontOfSize:12], NSFontAttributeName,
                            [NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName,
                            nil];

NSSize size = NSMakeSize(window.frame.size.width, 200);
myText.frame = [temp boundingRectWithSize:size options:NSLineBreakByWordWrapping | NSStringDrawingUsesLineFragmentOrigin attributes:attributes];

编辑:即使手动移动框架,很明显文本仍然会被截断。新调整的尺寸不完全在那里。

这是指: NSString boundingRectWithSize slightly underestimating the correct width - why?NSTextView or NSTextField automatically resize bounds / frame?

【问题讨论】:

  • 也许将高度从 200 更改为更大的值,以便框架大小知道垂直增长。
  • @rein 我一直在玩这个,虽然它确实重新调整了新框架的大小,但它仍然在底部剪裁文本。新框架不够大。请参阅更新后的问题以获取新的屏幕截图。

标签: objective-c nstextfield nstextview


【解决方案1】:

我遇到了同样的问题。我在the Documentation中找到了以下内容:

要正确绘制多行文本并调整其大小,请通过 options 参数中的 NSStringDrawingUsesLineFragmentOrigin。

此方法返回小数大小(在 返回 CGRect);要使用返回的大小来调整视图大小,您必须提出 使用 ceil 函数将其值设为最接近的较高整数。

所以这为我解决了:

CGRect rect = [myLabel.text boundingRectWithSize:CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)
                                                            options:NSStringDrawingUsesLineFragmentOrigin
                                                            attributes:@{NSFontAttributeName: myLabel.font}
                                                            context:nil];
rect.size.width = ceil(rect.size.width);
rect.size.height = ceil(rect.size.height);

更新 (Swift 5.1)

另一种 Swift 方法是:

let size = myLabel.text!.size(
    withAttributes: [.font: myLabel.font!]
)
let rect = CGSize(
  width: ceil(size.width),
  height: ceil(size.height)
)

有关 Objective-C 示例,请参阅 this answer

【讨论】:

  • 谢谢你,帮了我很多
  • 与 NSLineBreakByWordWrapping 的 OR'ing 无效,而且对我也不起作用。它不是 NSStringDrawingOptions 枚举的成员。
  • 嗯..你是对的!您是否仅使用NSStringDrawingUsesLineFragmentOrigin 尝试过?它奏效了吗?然后我会编辑 sn-p。
  • 大小通常是在您必须在标签下方添加项目时计算的。所以根据计算的高度计算尺寸并在标签下添加项目,对于标签调整,做[myLabel sizeToFit];
  • 谢谢!对我来说通用的答案是 RTFM :)
【解决方案2】:

有点迂回,但我发现查询NSTextFieldCell 比使用[NSAttributedString boundingRectWithSize:options:] 提供更准确/可靠的高度结果。

假设感兴趣的字符串已经在一个 NSTextField 中并设置了适当的格式/换行选项,然后查询文本单元格它认为它需要适合指定宽度的大小:

NSTextField* textField = ...

NSSize cellSize = [textField.cell cellSizeForBounds:NSMakeRect(0, 0, pathText.frame.size.width, CGFLOAT_MAX)];

cellSize.height 给出了文本在绘制时实际使用的高度。

【讨论】:

    【解决方案3】:

    这就是我最终采用的方法(至少目前是这样),它似乎工作正常,但我仍然觉得有更好的方法来实现这一点。

    NSString *temp = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel felis nec massa ultricies blandit non id arcu. Sed enim est. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel felis nec massa ultricies blandit non id arcu. Sed enim est.";
    
    myText.stringValue = temp;
    
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSFont systemFontOfSize:12], NSFontAttributeName,
                                [NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName,
                                nil];
    
    NSSize size = NSMakeSize(window.frame.size.width, MAXFLOAT);
    
    
    myText.frame = [temp boundingRectWithSize:size options:NSLineBreakByWordWrapping | NSStringDrawingUsesLineFragmentOrigin attributes:attributes];
    
    // Keep current width but add some more on the bottom
    NSSize tF = myText.frame.size;
    [myText setFrameSize:NSMakeSize(tF.width, tF.height + 35)];
    
    [myText setFrameOrigin:NSMakePoint((NSWidth(window.frame) - NSWidth(myText.frame)) / 2, 
                                       (NSHeight(window.frame) -  NSHeight(myText.frame) - 20))];
    
    [myText setAutoresizingMask:NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin];
    

    产生这个:

    【讨论】:

      【解决方案4】:

      我发现 NSString#boundingRectWithSize 从来都不是完全正确的,唯一似乎运作良好的是这里描述的那个: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html

      class func sizeForString(_ text : String, withFont font: NSFont, inWidth maxWidth: CGFloat) -> NSSize {
          let textStorage = NSTextStorage(string: text)
          let textContainer = NSTextContainer(containerSize: NSSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude))
          let layoutManager = NSLayoutManager()
          layoutManager.addTextContainer(textContainer)
          textStorage.addLayoutManager(layoutManager)
          textStorage.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, textStorage.length))
      textContainer.lineFragmentPadding = 0
          layoutManager.glyphRange(for: textContainer)
          return layoutManager.usedRect(for: textContainer).size
       }
      

      【讨论】:

        猜你喜欢
        • 2014-02-11
        • 2012-04-02
        • 2014-09-26
        • 1970-01-01
        • 1970-01-01
        • 2012-12-31
        • 2020-07-05
        • 1970-01-01
        • 2014-02-28
        相关资源
        最近更新 更多