IOS7-TextKit boudingRectWithSize:options:attributes:context的使用
(2013-12-12 09:50:47)
标签:
it |
分类: Mac/IOS那些事 |
原文地址:
之前用Text Kit写Reader的时候,在分页时要计算一段文本的尺寸大小,之前使用了NSString类的sizeWithFont:constrainedToSize:lineBreakMode:方法,但是该方法已经被iOS7 Deprecated了,而iOS7新出了一个boudingRectWithSize:options:attributes:context方法来代替:
很碍眼的黄色警告标志。
先来看看iOS7 SDK包中关于boudingRectWithSize:options:attributes:context方法的定义:
[cpp] view plaincopy
-
//
NOTE: All of the following methods will default to drawing on a baseline, limiting drawing to a single line. -
//
To correctly draw and size multi-line text, pass NSStringDrawingUsesLineF ragmentOrigin in the options parameter. -
@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其实也有一个同名的方法:
[cpp] view plaincopy
-
@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
参数
size
宽高限制,用于计算文本绘制时占据的矩形块。
The width and height constraints to apply when computing the string’s bounding rectangle.
options
文本绘制时的附加选项。可能取值请参考“NSStringDrawingOptions”。
context
context上下文。包括一些信息,例如如何调整字间距以及缩放。最终,该对象包含的信息将用于文本绘制。该参数可为 nil 。
返回值
一个矩形,大小等于文本绘制完将占据的宽和高。
讨论
可以使用该方法计算文本绘制所需的空间。size 参数是一个constraint ,用于在绘制文本时作为参考。但是,如果绘制完整个文本需要更大的空间,则返回的矩形大小可能比 size 更大。一般,绘制时会采用constraint 提供的宽度,但高度则会根据需要而定。
特殊情况
为了计算文本块的大小,该方法采用默认基线。
如果
NSStringDrawingUsesLineF
兼容性
- iOS 6.0 以后支持。
声明于
NSStringDrawing.
另外,关于参数(NSStringDrawingOptions)options
[cpp] view plaincopy
- typedef
NS_ENUM(NSInteger, NSStringDrawingOptions) { -
NSStringDrawingTruncates LastVisibleLine = 1 << 5, Truncates and adds the ellipsis character to the last visible line if the text doesn't fit into the bounds specified. Ignored if NSStringDrawingUsesLineF ragmentOrigin is not also set. -
NSStringDrawingUsesLineF ragmentOrigin = 1 << 0, The specified origin is the line fragment origin, not the base line origin -
NSStringDrawingUsesFontL eading = 1 << 1, Uses the font leading for calculating line heights -
NSStringDrawingUsesDevic eMetrics = 1 << 3, Uses image glyph bounds instead of typographic bounds -
}
NS_ENUM_AVAILABLE_IOS(6_0);
NSStringDrawingTruncates
如果文本内容超出指定的矩形限制,文本将被截去并在最后一个字符后加上省略号。如果没有指定NSStringDrawingUsesLineF
NSStringDrawingUsesLineF
绘制文本时使用 line fragement origin 而不是 baseline origin。
The origin specified when drawing the string is the line fragment origin and not the baseline origin.
NSStringDrawingUsesFontL
计算行高时使用行距。(译者注:字体大小+行间距=行距)
NSStringDrawingUsesDevic
计算布局时使用图元字形(而不是印刷字体)。
Use the image glyph bounds (instead of the typographic bounds) when computing layout.
简单写了一个Demo来看看该方法的使用,并比较了一下各个options的不同,首先是代码:
[cpp] view plaincopy
-
NSAttributedString
*attrStr = [[NSAttributedString alloc] initWithString:textView.text]; -
textView.attributedText
= attrStr; -
NSRange
range = NSMakeRange(0, attrStr.length); -
NSDictionary
*dic = [attrStr attributesAtIndex:0 effectiveRange:&range]; // 获取该段attributedString的属性字典 - //
计算文本的大小 -
CGSize
textSize = [textView.text boundingRectWithSize:textView.bounds.size // 用于计算文本绘制时占据的矩形块 -
options:NSStringDrawingUsesLineF ragmentOrigin | NSStringDrawingUsesFontL eading // 文本绘制时的附加选项 -
attributes:dic // 文字的属性 -
context:nil].size; // context上下文。包括一些信息,例如如何调整字间距以及缩放。该对象包含的信息将用于文本绘制。该参数可为nil - NSLog(@"w
= ,%f" textSize.width); - NSLog(@"h
= ,%f" textSize.height);
再看看不同的options下控制台的输出结果:
[cpp] view plaincopy
-
NSStringDrawingUsesLineF
ragmentOrigin | NSStringDrawingUsesFontL eading -
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 -
- NSStringDrawingUsesLineF
ragmentOrigin //The specified origin is the line fragment origin, not the base line origin -
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 -
- NSStringDrawingTruncates
LastVisibleLine //Truncates and adds the ellipsis character to the last visible line if the text doesn't fit into the bounds specified. Ignored if NSStringDrawingUsesLineF ragmentOrigin is not also set. -
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 -
- NSStringDrawingUsesFontL
eading //Uses the font leading for calculating line heights -
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 -
- NSStringDrawingUsesDevic
eMetrics //Uses image glyph bounds instead of typographic bounds -
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参数为NSStringDrawingUsesLineF
如果为NSStringDrawingTruncates
如果为NSStringDrawingUsesFontL
各个参数是可以组合使用的,如NSStringDrawingUsesLineF
根据该方法我调整了一下Reader的分页方法:(主要是将被iOS7 Deprecated的sizeWithFont:constrainedToSize:lineBreakMode:方法改成了boudingRectWithSize:options:attributes:context:方法来计算文本尺寸)
[cpp] view plaincopy
-
- -(BOOL)paging
- {
-
-
static const CGFloat textScaleFactor = 1.; // 设置文字比例 -
NSString *textStyle = [curPageView.textView tkd_textStyle]; // 设置文字样式 -
preferredFont_ = [UIFont tkd_preferredFontWithTextSty le:textStyle scale:textScaleFactor]; //设置prferredFont(包括样式和大小) -
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:NSStringDrawingUsesLineF ragmentOrigin -
attributes:dic -
context:nil].size; -
NSLog(@"w = ,%f" totalTextSize.width); -
NSLog(@"h = ,%f" totalTextSize.height); -
-
-
-
if (totalTextSize.height < height) { -
-
totalPages_ = 1; // 设定总页数为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); -
-
-
-
如果referCharactersPerPage过大,则直接调整至下限值,减少调整的时间 -
if (referCharactersPerPage > 1000) { -
referCharactersPerPage = 1000; -
} -
-
获取理想状态下的每页文本的范围和pageText及其尺寸 -
NSRange range = NSMakeRange(referCharactersPerPage, referCharactersPerPage); // 一般第一页字符数较少,所以取第二页的文本范围作为调整的参考标准 -
NSString *pageText = [bookItem.content.string substringWithRange:range]; // 获取该范围内的文本 -
NSLog(@"%@", pageText); -
-
-
NSRange ptrange = NSMakeRange(0, pageText.length); -
NSDictionary *ptdic = [[bookItem.content attributedSubstringFromR ange:ptrange] attributesAtIndex:0 effectiveRange:&ptrange]; -
CGSize pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size -
options:NSStringDrawingUsesLineF ragmentOrigin -
attributes:ptdic -
context:nil].size; -
-
若pageText超出text view的显示范围,则调整referCharactersPerPage -
NSLog(@"height = ,%d" height); -
while (pageTextSize.height > height) { -
NSLog(@"pageTextSize.height = ,%f" pageTextSize.height); -
referCharactersPerPage -= 2; // 每页字符数减2 -
range = NSMakeRange(0, referCharactersPerPage); // 重置每页字符的范围 -
ptdic = [[bookItem.content attributedSubstringFromR ange:range] attributesAtIndex:0 effectiveRange:&range]; -
CGSize pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size -
options:NSStringDrawingUsesLineF ragmentOrigin -
attributes:ptdic -
context:nil].size; -
pageText = [bookItem.content.string substringWithRange:range]; // 重置pageText -
-
pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size -
options:NSStringDrawingUsesLineF ragmentOrigin -
attributes:ptdic -
context:nil].size; // 获取pageText的尺寸 -
} -
-
根据调整后的referCharactersPerPage设定好charsPerPage_ -
charsPerPage_ = referCharactersPerPage; -
NSLog(@"cpp: %d" ,charsPerPage_); -
-
计算totalPages_ -
totalPages_ = (int)bookItem.content.length / charsPerPage_ + 1; -
NSLog(@"ttp: %d" ,totalPages_); -
-
计算最后一页的字符数,防止范围溢出 -
charsOfLastPage_ = textLength_ - (totalPages_ - 1) * charsPerPage_; -
NSLog(@"colp: %d" ,charsOfLastPage_); -
-
// 分页完成 -
return YES; -
} - }
这样就看不到碍眼的黄色警告标志了。