以前用Text Kit寫Reader的時候,在分頁時要計算一段文本的尺寸大小,以前使用了NSString類的sizeWithFont:constrainedToSize:lineBreakMode:方法,可是該方法已經被iOS7 Deprecated了,而iOS7新出了一個boudingRectWithSize:options:attributes:context方法來代替:html

很礙眼的黃色警告標誌。ios
先來看看iOS7 SDK包中關於boudingRectWithSize:options:attributes:context方法的定義:app
- @interface NSString (NSExtendedStringDrawing)
- - (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(7_0);
- - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(7_0);
- @end
關於該方法,NSAttributedString其實也有一個同名的方法:
- @interface NSAttributedString (NSExtendedStringDrawing)
- - (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
- - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
- @end
該方法在iOS6就可使用了。
關於該類,有一篇關於NSAttributedString UIKit Additions Reference翻譯的文章:http://blog.csdn.net/kmyhy/article/details/8895643佈局
裏面就說到了該方法:字體
boundingRectWithSize:options:context:ui
返回文本繪製所佔據的矩形空間。spa
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context.net
參數翻譯
sizehtm
寬高限制,用於計算文本繪製時佔據的矩形塊。
The width and height constraints to apply when computing the string’s bounding rectangle.
options
文本繪製時的附加選項。可能取值請參考「NSStringDrawingOptions」。
context
context上下文。包括一些信息,例如如何調整字間距以及縮放。最終,該對象包含的信息將用於文本繪製。該參數可爲 nil 。
返回值
一個矩形,大小等於文本繪製完將佔據的寬和高。
討論
可使用該方法計算文本繪製所需的空間。size 參數是一個constraint ,用於在繪製文本時做爲參考。可是,若是繪製完整個文本須要更大的空間,則返回的矩形大小可能比 size 更大。通常,繪製時會採用constraint 提供的寬度,但高度則會根據須要而定。
特殊狀況
爲了計算文本塊的大小,該方法採用默認基線。
若是 NSStringDrawingUsesLineFragmentOrigin未指定,矩形的高度將被忽略,同時使用單線繪製。(因爲一個 bug,在 iOS6 中,寬度會被忽略)
兼容性
聲明於
NSStringDrawing.
另外,關於參數(NSStringDrawingOptions)options
- typedef NS_ENUM(NSInteger, NSStringDrawingOptions) {
- NSStringDrawingTruncatesLastVisibleLine = 1 << 5,
- NSStringDrawingUsesLineFragmentOrigin = 1 << 0,
- NSStringDrawingUsesFontLeading = 1 << 1,
- NSStringDrawingUsesDeviceMetrics = 1 << 3,
- } NS_ENUM_AVAILABLE_IOS(6_0);
NSStringDrawingTruncatesLastVisibleLine:
若是文本內容超出指定的矩形限制,文本將被截去並在最後一個字符後加上省略號。若是沒有指定NSStringDrawingUsesLineFragmentOrigin選項,則該選項被忽略。
NSStringDrawingUsesLineFragmentOrigin:
繪製文本時使用 line fragement origin 而不是 baseline origin。
The origin specified when drawing the string is the line fragment origin and not the baseline origin.
NSStringDrawingUsesFontLeading:
計算行高時使用行距。(譯者注:字體大小+行間距=行距)
NSStringDrawingUsesDeviceMetrics:
計算佈局時使用圖元字形(而不是印刷字體)。
Use the image glyph bounds (instead of the typographic bounds) when computing layout.
簡單寫了一個Demo來看看該方法的使用,並比較了一下各個options的不一樣,首先是代碼:
- NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:textView.text];
- textView.attributedText = attrStr;
- NSRange range = NSMakeRange(0, attrStr.length);
- NSDictionary *dic = [attrStr attributesAtIndex:0 effectiveRange:&range];
- CGSize textSize = [textView.text boundingRectWithSize:textView.bounds.size
- options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
- attributes:dic
- context:nil].size;
- NSLog(@"w = %f", textSize.width);
- NSLog(@"h = %f", textSize.height);
再看看不一樣的options下控制檯的輸出結果:
- NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
- 2013-09-02 21:04:47.470 BoudingRect_i7_Demo[3532:a0b] w = 322.171875
- 2013-09-02 21:04:47.471 BoudingRect_i7_Demo[3532:a0b] h = 138.000015
-
- NSStringDrawingUsesLineFragmentOrigin
- 2013-09-02 17:35:40.547 BoudingRect_i7_Demo[1871:a0b] w = 318.398438
- 2013-09-02 17:35:40.549 BoudingRect_i7_Demo[1871:a0b] h = 69.000000
-
- NSStringDrawingTruncatesLastVisibleLine
- 2013-09-02 17:37:38.398 BoudingRect_i7_Demo[1902:a0b] w = 1523.408203
- 2013-09-02 17:37:38.400 BoudingRect_i7_Demo[1902:a0b] h = 13.800000
-
- NSStringDrawingUsesFontLeading
- 2013-09-02 17:40:45.903 BoudingRect_i7_Demo[1932:a0b] w = 1523.408203
- 2013-09-02 17:40:45.905 BoudingRect_i7_Demo[1932:a0b] h = 13.800000
-
- NSStringDrawingUsesDeviceMetrics
- 2013-09-02 17:42:03.283 BoudingRect_i7_Demo[1956:a0b] w = 1523.408203
- 2013-09-02 17:42:03.284 BoudingRect_i7_Demo[1956:a0b] h = 13.800000
其中若是options參數爲NSStringDrawingUsesLineFragmentOrigin,那麼整個文本將以每行組成的矩形爲單位計算整個文本的尺寸。(在這裏有點奇怪,由於字體高度大概是13.8,textView中大概有10行文字,此時用該選項計算出來的只有5行,即高度爲69,而同時使用NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin卻能夠得出文字恰好有10行,即高度爲138,這裏要等iOS7官方的文檔出來再看看選項的說明,由於畢竟以上文檔是iOS6的東西)
若是爲NSStringDrawingTruncatesLastVisibleLine或者NSStringDrawingUsesDeviceMetric,那麼計算文本尺寸時將以每一個字或字形爲單位來計算。
若是爲NSStringDrawingUsesFontLeading則以字體間的行距(leading,行距:從一行文字的底部到另外一行文字底部的間距。)來計算。
各個參數是能夠組合使用的,如NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine。
根據該方法我調整了一下Reader的分頁方法:(主要是將被iOS7 Deprecated的sizeWithFont:constrainedToSize:lineBreakMode:方法改爲了boudingRectWithSize:options:attributes:context:方法來計算文本尺寸)
- -(BOOL)paging
- {
-
- static const CGFloat textScaleFactor = 1.;
- NSString *textStyle = [curPageView.textView tkd_textStyle];
- preferredFont_ = [UIFont tkd_preferredFontWithTextStyle:textStyle scale:textScaleFactor];
- NSLog(@"paging: %@", preferredFont_.fontDescriptor.fontAttributes);
-
-
-
- NSUInteger height = (int)self.view.bounds.size.height - 40.0;
-
-
-
- NSDictionary *dic = preferredFont_.fontDescriptor.fontAttributes;
- CGSize totalTextSize = [bookItem.content.string boundingRectWithSize:curPageView.textView.bounds.size
- options:NSStringDrawingUsesLineFragmentOrigin
- attributes:dic
- context:nil].size;
- NSLog(@"w = %f", totalTextSize.width);
- NSLog(@"h = %f", totalTextSize.height);
-
-
-
- if (totalTextSize.height < height) {
-
- totalPages_ = 1;
- charsPerPage_ = [bookItem.content length];
- textLength_ = [bookItem.content length];
- return NO;
- }
- else {
-
- textLength_ = [bookItem.content length];
- NSUInteger referTotalPages = (int)totalTextSize.height / (int)height + 1;
- NSUInteger referCharactersPerPage = textLength_ / referTotalPages;
-
- NSLog(@"textLength = %d", textLength_);
- NSLog(@"referTotalPages = %d", referTotalPages);
- NSLog(@"referCharactersPerPage = %d", referCharactersPerPage);
-
-
-
-
- if (referCharactersPerPage > 1000) {
- referCharactersPerPage = 1000;
- }
-
-
- NSRange range = NSMakeRange(referCharactersPerPage, referCharactersPerPage);
- NSString *pageText = [bookItem.content.string substringWithRange:range];
- NSLog(@"%@", pageText);
-
-
- NSRange ptrange = NSMakeRange(0, pageText.length);
- NSDictionary *ptdic = [[bookItem.content attributedSubstringFromRange:ptrange] attributesAtIndex:0 effectiveRange:&ptrange];
- CGSize pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size
- options:NSStringDrawingUsesLineFragmentOrigin
- attributes:ptdic
- context:nil].size;
-
-
- NSLog(@"height = %d", height);
- while (pageTextSize.height > height) {
- NSLog(@"pageTextSize.height = %f", pageTextSize.height);
- referCharactersPerPage -= 2;
- range = NSMakeRange(0, referCharactersPerPage);
- ptdic = [[bookItem.content attributedSubstringFromRange:range] attributesAtIndex:0 effectiveRange:&range];
- CGSize pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size
- options:NSStringDrawingUsesLineFragmentOrigin
- attributes:ptdic
- context:nil].size;
- pageText = [bookItem.content.string substringWithRange:range];
-
- pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size
- options:NSStringDrawingUsesLineFragmentOrigin
- attributes:ptdic
- context:nil].size;
- }
-
-
- charsPerPage_ = referCharactersPerPage;
- NSLog(@"cpp: %d", charsPerPage_);
-
-
- totalPages_ = (int)bookItem.content.length / charsPerPage_ + 1;
- NSLog(@"ttp: %d", totalPages_);
-
-
- charsOfLastPage_ = textLength_ - (totalPages_ - 1) * charsPerPage_;
- NSLog(@"colp: %d", charsOfLastPage_);
-
-
- return YES;
- }
- }
這樣就看不到礙眼的黃色警告標誌了。
重要的是,因爲該方法計算文本的尺寸更爲準確,因此可使得分頁後頁與頁之間的連貫性好了不少,並且每頁的空間利用率都提升了不少,每頁的文字幾乎鋪滿了整個頁面。


