http://blog.csdn.net/jymn_chen/article/details/10949279
之前用Text Kit写Reader的时候,在分页时要计算一段文本的尺寸大小,之前使用了NSString类的sizeWithFont:constrainedToSize:lineBreakMode:方法,但是该方法已经被iOS7 Deprecated了,而iOS7新出了一个boudingRectWithSize:options:attributes:context方法来代替:
很碍眼的黄色警告标志。
先来看看iOS7 SDK包中关于boudingRectWithSize:options:attributes:context方法的定义:
-
-
-
@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:
返回文本绘制所占据的矩形空间。
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context
参数
size
宽高限制,用于计算文本绘制时占据的矩形块。
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;
-
}
-
}
这样就看不到碍眼的黄色警告标志了。
重要的是,由于该方法计算文本的尺寸更为准确,所以可以使得分页后页与页之间的连贯性好了很多,而且每页的空间利用率都提高了很多,每页的文字几乎铺满了整个页面。
阅读(1267) | 评论(0) | 转发(0) |