2010-02-17 86 views
43

我想做的事情在固定宽度的盒子NSAttributedStrings的一些图纸,但我有麻烦的计算得出时,他们会采取了合适的高度,以获得高度NSAttributedString。到目前为止,我已经试过:如何在一个固定的宽度

  1. 调用- (NSSize) size,但结果是无用的(为了这个目的),因为他们会给任何宽度的字符串的欲望。

  2. 调用- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options用矩形切换到我想要的宽度和NSStringDrawingUsesLineFragmentOrigin在选项中,就像我在绘图中使用的一样。结果很难理解;当然不是我要找的东西。 (正如指出在许多地方,包括this可可-DEV线程)。

  3. 创建临时NSTextView和做:
    [[tmpView textStorage] setAttributedString:aString];
    [tmpView setHorizontallyResizable:NO];
    [tmpView sizeToFit];

    当我查询tmpView的边框,宽度为仍需要,并高度往往是正确的...直到我得到更长的字符串,当它的通常是所需尺寸的一半。 (似乎没有成为一个最大尺寸被击中:一帧将273.0高(约300太短),其他的将是478.0(仅60十岁上下太短))。

我很感激任何指针,如果其他人已经管理了这一点。

回答

15

答案使用
- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options
rect你传递应该在你想成为无限(其中,呃,是非常合情合理的)尺寸0.0。示例here

+2

此答案已过时。 [格雷厄姆的回答](http://stackoverflow.com/a/2460091/39155)下面是截至2014年的正确方法。 – 2014-08-17 16:47:47

6

您可能感兴趣Jerry Krinock's great(仅限OS X)NS(Attributed)String+Geometrics类别,该类别旨在完成各种字符串测量,包括您要查找的内容。

+1

该代码似乎是Mac特定的。它不会帮助iOS开发。 – Brennan 2013-08-23 22:36:21

+3

你说得对,问题是关于'NSTextView',它是一个Mac类。当我回答这个问题时,我甚至不确定iOS是否有'NSAttributedString'。 – 2013-08-24 02:46:17

+1

后期输入,但只是一个头:我曾经有过NS(Attributed)String + Geometrics一直低估长字符串所需高度的问题。到现在为止,我其实已经通过增加额外的25%来掩盖结果。我现在正在寻找一个更新,更好的解决方案。我不认为NS(Attributed)String + Geometrics在10.9,10.10和10.11上运行良好。 – Bryan 2015-09-15 01:46:47

31
-[NSAttributedString boundingRectWithSize:options:] 

你可以指定NSStringDrawingUsesDeviceMetrics得到union of all glyph bounds

-[NSAttributedString size]不同,返回的NSRect表示在绘制字符串时将会改变的区域的尺寸。

由于@Bryan意见,boundingRectWithSize:options:已被弃用(不推荐)OS X 10.11及更高版本。这是因为根据上下文,字符串样式现在是动态的。

对于OS X 10.11及更高版本,看看苹果的Calculating Text Height开发者文档。

+0

看来如果你使用'NSStringDrawingUsesDeviceMetrics'并且没有字形会返回'0'。有办法处理这两种情况吗?或者你必须知道或了解你是否添加了一个字形? (在iOS 8上测试过) – zekel 2014-10-28 21:28:25

+0

有意义的是,没有可见内容的字符串将返回零大小的矩形。您是否看到iOS 8与iOS 7相比有新的行为? – 2014-10-29 05:22:57

+0

我的意思是说,如果你有一个带有文本(而且没有字形)的'NSAttributedString',并且你使用'NSStringDrawingUsesDeviceMetrics',那么大小就是'CGSizeZero'。因此,在决定如何获得尺寸之前,您似乎需要知道是否有字形... – zekel 2014-11-01 08:50:05

2

使用NSAttributedString方法

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context 

大小是上的区域中的约束,计算出的区域的宽度被限制在指定的宽度而高度是柔性的基于这个宽度。如果不可用,可以指定nil作为上下文。要获得多行文本大小,请使用NSStringDrawingUsesLineFragmentOrigin来获取选项。

1

我只是浪费了大量的时间在这,所以我提供了一个附加的应答挽救他人的未来。格雷厄姆的答案是90%正确的,但它缺少一个关键部分:

为了获得准确的结果与-boundingRectWithSize:options:你必须通过下列选项

NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesDeviceMetrics|NSStringDrawingUsesFontLeading` 

如果省略lineFragmentOrigin一个,你会废话回来;返回的矩形将是单线高位,并且完全不会影响您传入方法的大小。

为什么这是如此复杂,如此糟糕的记录超越了我。但是你现在有了。通过这些选项,它会完美地工作(至少在OS X上)。

+0

另外:这假定你有一个NSAttributedString创建一个给定的字体和你正在寻找的NSParagraphStyle - 在我的情况下,这是一个左对齐的,包装,没有连字符段落风格。不要忘记创建你的时候创建你的Javastring。 – Bryan 2015-09-15 02:19:41

+0

此方法在10.11+已弃用,不再正常工作; El Capitan的返回高度太小。 – Bryan 2015-10-17 04:33:02

1

在OS X 10.11+,下面的方法对我的作品(从苹果公司的Calculating Text Height文件)

- (CGFloat)heightForString:(NSAttributedString *)myString atWidth:(float)myWidth 
{ 
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:myString]; 
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: 
     NSMakeSize(myWidth, FLT_MAX)]; 
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; 
    [layoutManager addTextContainer:textContainer]; 
    [textStorage addLayoutManager:layoutManager]; 
    [layoutManager glyphRangeForTextContainer:textContainer]; 
    return [layoutManager 
     usedRectForTextContainer:textContainer].size.height; 
} 
0

在该页上没有一个单一的答案为我工作,也没有从古代的旧Objective-C代码Apple's documentation。我终于没有机会到UITextView首先设置它的textattributedText属性,然后计算需要这样大小的工作:

let size = textView.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.max)) 

完美的作品。 Booyah!

1

斯威夫特3:

let attributedStringToMeasure = NSAttributedString(string: textView.text, attributes: [ 
     NSFontAttributeName: UIFont(name: "GothamPro-Light", size: 15)!, 
     NSForegroundColorAttributeName: ClickUpConstants.defaultBlackColor 
]) 

let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: widthOfActualTextView, height: 10)) 
placeholderTextView.attributedText = attributedStringToMeasure 
let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) 

height = size.height 

这个答案的伟大工程对我来说,不像是给我的不正确的高度较大串其他的。

如果你想与普通的文本,而不是归因文字要做到这一点,做到以下几点:

let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: ClickUpConstants.screenWidth - 30.0, height: 10)) 
placeholderTextView.text = "Some text" 
let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) 

height = size.height 
0

正如很多关于我的测试上面提到的球员,和基地。

我在iOS上使用open func boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRect这样的怒吼:

let rect = attributedTitle.boundingRect(with: CGSize(width:200, height:0), options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil) 

这里200是固定宽度为您的预期,高度我给它0,因为我认为这是更好的一种告诉API高度是无限制

选项在这里并不重要,我试试.usesLineFragmentOrigin.usesLineFragmentOrigin.union(.usesFontLeading).usesLineFragmentOrigin.union(.usesFontLeading).union(.usesDeviceMetrics),它给出了相同的结果。

而结果是预计为我的。

谢谢。

2

我有一个复杂的具有多种字体的属性字符串,并得到不正确的结果,我首先尝试了一些上述答案。使用UITextView给了我正确的高度,但对于我的用例来说太慢了(确定收集单元的大小)。我使用前面引用的并由Erik描述的Apple doc中描述的相同的一般方法编写了快速代码。这给了我正确的结果,必须比UITextView做更快的执行计算。

private func heightForString(_ str : NSAttributedString, width : CGFloat) -> CGFloat { 
    let ts = NSTextStorage(attributedString: str) 

    let size = CGSize(width:width, height:CGFloat.greatestFiniteMagnitude) 

    let tc = NSTextContainer(size: size) 
    tc.lineFragmentPadding = 0.0 

    let lm = NSLayoutManager() 
    lm.addTextContainer(tc) 

    ts.addLayoutManager(lm) 
    lm.glyphRange(forBoundingRect: CGRect(origin:CGPoint(x:0,y:0),size:size), in: tc) 

    let rect = lm.usedRect(for: tc) 
    return rect.size.height 
} 
+0

像一个魅力工作 – Harish 2018-01-17 06:26:30