2010-02-17 79 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