2013-08-19 95 views
26

我有一個讓我對給定字符串的長度一個UITextView完美的大小(與相應的正確的字體大小)的方法:我應該如何替換已棄用的sizeWithFont:方法?

- (NSInteger) heightOfLabel:(NSString*) string { 
    CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX); 
    CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string] 
      sizeWithFont:[UIFont systemFontOfSize:15] 
      constrainedToSize:maximumLabelSize 
      lineBreakMode:NSLineBreakByWordWrapping]; 

    return expectedLabelSize.height + 5; 
} 

事實上,它仍然給了我一個完美的結合,即使在iOS7 。雖然現在它提出了一個警告方法,說我不應該使用'sizeWithFont:contrainedToSize:lineBreakMode'。

現在說我應該使用-boundingRectWithSize:選項:屬性:背景:

這種方法是不是新來iOS7,因此我估計,它是好的要問它的堆棧溢出,而不是去跨越官方蘋果開發者論壇。

我有三個問題:

1)因爲它已被棄用,這是否意味着我一定要更換它,儘管它仍然工作? 2)我已經嘗試了許多不同的boundingRectWithSize:方法,它有着各種變量,但它從來都不是完美的,它似乎總是略微出現(就像許多stackoverflow問題指出的那樣) - 是否有一個完美的替代品,這個沒有廢棄的方法與我以前的方法完全一樣,最簡單的麻煩是什麼?

3)爲什麼要刪除這個方法?是否因爲與其他方法重疊?

+0

轉寄此[鏈接](http://www.cnblogs.com/lisa090818/p/3445161.html )。 – yazh

+1

wtf是那個鏈接? – Rambatino

回答

57

審判錯誤的一個小時我設法讓後它的工作:

CGSize maximumLabelSize = CGSizeMake(tableView.width, MAXFLOAT); 

NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine | 
           NSStringDrawingUsesLineFragmentOrigin; 

NSDictionary *attr = @{NSFontAttributeName: [UIFont systemFontOfSize:15]}; 
CGRect labelBounds = [string boundingRectWithSize:maximumLabelSize 
              options:options 
             attributes:attr 
              context:nil]; 

更新:

由於T先生在下面的答案中提到:在iOS系統7及更高版本,此方法返回小數大小(在返回的CGRect的大小組件中);要使用返回的大小來調整視圖大小,您必須使用ceil函數將其值提高到最接近的較大整數。推薦使用ceilf功能。

CGFloat height = ceilf(labelBounds.size.height); 
+1

謝謝你。我現在使用類似於iOS6的東西,它使用您創建的stringAttributes字典創建NSAttributedString,並在屬性字符串上調用boundingRectWithSize:options:context:。 – AidenMontgomery

+0

比你!真的有用! – Andres

13

我相信,因爲該系列的NSString + UIKit的功能都是基於UIStringDrawing庫,這是不是線程安全的功能已被否決。如果你試圖在主線程上運行它們(就像任何其他UIKit功能一樣),你會得到不可預知的行爲。特別是,如果您同時在多個線程上運行該功能,它可能會導致應用程序崩潰。這就是爲什麼在iOS 6中,他們爲NSAttributedStrings引入了一個boundingRectWithSize:...方法。這是建立在NSStringDrawing庫之上的,並且是線程安全的。

如果您查看新的NSString boundingRectWithSize:...函數,它將以與NSAttributeString相同的方式請求屬性數組。如果我不得不猜測,iOS 7中的這個新的NSString函數僅僅是iOS 6的NSAttributeString函數的一個包裝。

在那個筆記上,如果你只支持iOS 6和iOS 7,那麼我肯定會改變所有你的NSString的sizeWithFont:...到NSAttributeString的boundingRectWithSize。如果你碰巧有一個奇怪的多線程案例,它會爲你節省很多頭痛!下面是如何轉換的NSString的sizeWithFont:constrainedToSize:

曾經被認爲是:

NSString *text = ...; 
CGFloat width = ...; 
UIFont *font = ...; 
CGSize size = [text sizeWithFont:font 
       constrainedToSize:CGSizeMake(width, CGFLOAT_MAX)]; 

可以替換爲:

NSString *text = ...; 
CGFloat width = ...; 
UIFont *font = ...; 
NSAttributedString *attributedText = 
    [[NSAttributedString alloc] 
     initWithString:text 
     attributes:@ 
     { 
      NSFontAttributeName: font 
     }]; 
CGRect rect = [attributedText boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) 
              options:NSStringDrawingUsesLineFragmentOrigin 
              context:nil]; 
CGSize size = rect.size; 

請注意文檔中提到:

在iOS系統7然後,此方法返回小數大小(返回的CGRect的大小爲 組件);要使用返回的大小來設置 的視圖,則必須使用ceil函數將其值提高到最接近的較大整數 。

於是拔出計算的高度或寬度用於上漿的意見,我會用:

CGFloat height = ceilf(size.height); 
CGFloat width = ceilf(size.width); 
+4

不解決linebreakmode問題 – Firdous

+0

請參閱下面的答案。 –

5

對於斷行的問題:

- (CGFloat)heightNeededForText:(NSString *)text withFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode { 
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 
     paragraphStyle.lineBreakMode = lineBreakMode; 
    CGSize size = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) 
            options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) 
            attributes:@{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle } 
            context:nil].size; 

    return ceilf(size.height); 
} 
2

的斯威夫特版本亞歷山大挪威的答案...

func heightNeededForText(text: NSString, withFont font: UIFont, width: CGFloat, lineBreakMode:NSLineBreakMode) -> CGFloat { 
     let paragraphStyle = NSMutableParagraphStyle() 
     paragraphStyle.lineBreakMode = lineBreakMode 
     let size: CGSize = text.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle], context: nil).size//text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MA 

     return ceil(size.height); 
    } 

在你想要得到的高度只需調用像下面的方法的代碼...

let size = self.heightNeededForText(text as NSString, withFont: UIFont.systemFontOfSize(15.0), width: scrollView.frame.size.width - 20, lineBreakMode: NSLineBreakMode.ByWordWrapping) //Can edit the font size and LinebreakMode 
相關問題