iOS7计算文本尺寸新方法

之前用Text Kit写Reader的时候,在分页时要计算一段文本的尺寸大小,之前使用了NSString类的sizeWithFont:constrainedToSize:lineBreakMode:方法,但是该方法已经被iOS7 Deprecated了,而iOS7新出了一个boudingRectWithSize:options:attributes:context方法来代替

 很碍眼的黄色警告标志。
先来看看iOS7 SDK包中关于boudingRectWithSize:options:attributes:context方法的定义:

  
  
  1. // NOTE: All of the following methods will default to drawing on a baseline, limiting drawing to a single line. 
  2. // To correctly draw and size multi-line text, pass NSStringDrawingUsesLineFragmentOrigin in the options parameter. 
  3. @interface NSString (NSExtendedStringDrawing) 
  4. - (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(7_0); 
  5. - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(7_0); 
  6. @end 

关于该方法,NSAttributedString其实也有一个同名的方法:

  
  
  1. @interface NSAttributedString (NSExtendedStringDrawing) 
  2. - (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0); 
  3. - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0); 
  4. @end 
  
  
  1. typedef NS_ENUM(NSInteger, NSStringDrawingOptions) { 
  2.     NSStringDrawingTruncatesLastVisibleLine = 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 NSStringDrawingUsesLineFragmentOrigin is not also set. 
  3.     NSStringDrawingUsesLineFragmentOrigin = 1 << 0, // The specified origin is the line fragment origin, not the base line origin 
  4.     NSStringDrawingUsesFontLeading = 1 << 1, // Uses the font leading for calculating line heights 
  5.     NSStringDrawingUsesDeviceMetrics = 1 << 3, // Uses image glyph bounds instead of typographic bounds 
  6. } NS_ENUM_AVAILABLE_IOS(6_0); 
  
  
  1. NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:textView.text]; 
  2. textView.attributedText = attrStr
  3. NSRange range = NSMakeRange(0, attrStr.length); 
  4. NSDictionary *dic = [attrStr attributesAtIndex:0 effectiveRange:&range];   // 获取该段attributedString的属性字典 
  5. // 计算文本的大小 
  6. CGSize textSize = [textView.text boundingRectWithSize:textView.bounds.size // 用于计算文本绘制时占据的矩形块 
  7.                                               options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading // 文本绘制时的附加选项 
  8.                                            attributes:dic        // 文字的属性 
  9.                                               context:nil].size; // context上下文。包括一些信息,例如如何调整字间距以及缩放。该对象包含的信息将用于文本绘制。该参数可为nil 
  10. NSLog(@"w = %f", textSize.width); 
  11. NSLog(@"h = %f", textSize.height); 

再看看不同的options下控制台的输出结果:

  
  
  1. NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading 
  2. 2013-09-02 21:04:47.470 BoudingRect_i7_Demo[3532:a0b] w = 322.171875 
  3. 2013-09-02 21:04:47.471 BoudingRect_i7_Demo[3532:a0b] h = 138.000015 
  4.  
  5. NSStringDrawingUsesLineFragmentOrigin // The specified origin is the line fragment origin, not the base line origin 
  6. 2013-09-02 17:35:40.547 BoudingRect_i7_Demo[1871:a0b] w = 318.398438 
  7. 2013-09-02 17:35:40.549 BoudingRect_i7_Demo[1871:a0b] h = 69.000000 
  8.  
  9. NSStringDrawingTruncatesLastVisibleLine // Truncates and adds the ellipsis character to the last visible line if the text doesn''t fit into the bounds specified. Ignored if NSStringDrawingUsesLineFragmentOrigin is not also set. 
  10. 2013-09-02 17:37:38.398 BoudingRect_i7_Demo[1902:a0b] w = 1523.408203 
  11. 2013-09-02 17:37:38.400 BoudingRect_i7_Demo[1902:a0b] h = 13.800000 
  12.  
  13. NSStringDrawingUsesFontLeading // Uses the font leading for calculating line heights 
  14. 2013-09-02 17:40:45.903 BoudingRect_i7_Demo[1932:a0b] w = 1523.408203 
  15. 2013-09-02 17:40:45.905 BoudingRect_i7_Demo[1932:a0b] h = 13.800000 
  16.  
  17. NSStringDrawingUsesDeviceMetrics // Uses image glyph bounds instead of typographic bounds 
  18. 2013-09-02 17:42:03.283 BoudingRect_i7_Demo[1956:a0b] w = 1523.408203 
  19. 2013-09-02 17:42:03.284 BoudingRect_i7_Demo[1956:a0b] h = 13.800000 
  
  
  1. /* 判断是否需要分页和进行分页动作 */ 
  2. -(BOOL)paging 
  3.     /* 获取Settings中设定好的字体(主要是获取字体大小) */ 
  4.     static const CGFloat textScaleFactor = 1.; // 设置文字比例 
  5.     NSString *textStyle = [curPageView.textView tkd_textStyle]; // 设置文字样式 
  6.     preferredFont_ = [UIFont tkd_preferredFontWithTextStyle:textStyle scale:textScaleFactor]; //设置prferredFont(包括样式和大小) 
  7.     NSLog(@"paging: %@", preferredFont_.fontDescriptor.fontAttributes); // 在控制台中输出字体的属性字典 
  8.      
  9.      
  10.     /* 设定每页的页面尺寸 */ 
  11.     NSUInteger height = (int)self.view.bounds.size.height - 40.0; // 页面的高度 
  12.      
  13.      
  14.     /* 获取文本的总尺寸 */ 
  15.     NSDictionary *dic = preferredFont_.fontDescriptor.fontAttributes; 
  16.     CGSize totalTextSize = [bookItem.content.string boundingRectWithSize:curPageView.textView.bounds.size 
  17.                                                                  options:NSStringDrawingUsesLineFragmentOrigin 
  18.                                                               attributes:dic 
  19.                                                                  context:nil].size; 
  20.     NSLog(@"w = %f", totalTextSize.width); 
  21.     NSLog(@"h = %f", totalTextSize.height); 
  22.      
  23.      
  24.     /* 开始分页 */ 
  25.     if (totalTextSize.height < height) { 
  26.         /* 如果一页就能显示完,直接显示所有文本 */ 
  27.         totalPages_   = 1;             // 设定总页数为1 
  28.         charsPerPage_ = [bookItem.content length]; // 设定每页的字符数 
  29.         textLength_   = [bookItem.content length]; // 设定文本总长度 
  30.         return NO;                     // 不用分页 
  31.     } 
  32.     else { 
  33.         /* 计算理想状态下的页面数量和每页所显示的字符数量,用来作为参考值用 */ 
  34.         textLength_                       = [bookItem.content length];                   // 文本的总长度 
  35.         NSUInteger referTotalPages        = (int)totalTextSize.height / (int)height + 1; // 理想状态下的总页数 
  36.         NSUInteger referCharactersPerPage = textLength_ / referTotalPages;               // 理想状态下每页的字符数 
  37.         // 输出理想状态下的参数信息 
  38.         NSLog(@"textLength             = %d", textLength_); 
  39.         NSLog(@"referTotalPages        = %d", referTotalPages); 
  40.         NSLog(@"referCharactersPerPage = %d", referCharactersPerPage); 
  41.          
  42.          
  43.         /* 根据referCharactersPerPage和text view的高度开始动态调整每页的字符数 */ 
  44.         // 如果referCharactersPerPage过大,则直接调整至下限值,减少调整的时间 
  45.         if (referCharactersPerPage > 1000) { 
  46.             referCharactersPerPage = 1000
  47.         } 
  48.          
  49.         // 获取理想状态下的每页文本的范围和pageText及其尺寸 
  50.         NSRange range       = NSMakeRange(referCharactersPerPage, referCharactersPerPage); // 一般第一页字符数较少,所以取第二页的文本范围作为调整的参考标准 
  51.         NSString *pageText  = [bookItem.content.string substringWithRange:range]; // 获取该范围内的文本 
  52.         NSLog(@"%@", pageText); 
  53.          
  54.          
  55.         NSRange ptrange = NSMakeRange(0, pageText.length); 
  56.         NSDictionary *ptdic = [[bookItem.content attributedSubstringFromRange:ptrange] attributesAtIndex:0 effectiveRange:&ptrange]; 
  57.         CGSize pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size 
  58.                                                      options:NSStringDrawingUsesLineFragmentOrigin 
  59.                                                   attributes:ptdic 
  60.                                                      context:nil].size; 
  61.          
  62.         // 若pageText超出text view的显示范围,则调整referCharactersPerPage 
  63.         NSLog(@"height = %d", height); 
  64.         while (pageTextSize.height > height) {  
  65.             NSLog(@"pageTextSize.height = %f", pageTextSize.height); 
  66.             referCharactersPerPage -2;                                      // 每页字符数减2 
  67.             range                   = NSMakeRange(0, referCharactersPerPage); // 重置每页字符的范围 
  68.             ptdic = [[bookItem.content attributedSubstringFromRange:range] attributesAtIndex:0 effectiveRange:&range]; 
  69.             CGSize pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size 
  70.                                                          options:NSStringDrawingUsesLineFragmentOrigin 
  71.                                                       attributes:ptdic 
  72.                                                          context:nil].size; 
  73.             pageText                = [bookItem.content.string substringWithRange:range];        // 重置pageText 
  74.              
  75.             pageTextSize = [pageText boundingRectWithSize:curPageView.textView.bounds.size 
  76.                                                   options:NSStringDrawingUsesLineFragmentOrigin 
  77.                                                attributes:ptdic 
  78.                                                   context:nil].size; // 获取pageText的尺寸 
  79.         } 
  80.          
  81.         // 根据调整后的referCharactersPerPage设定好charsPerPage_ 
  82.         charsPerPage_ = referCharactersPerPage;  
  83.         NSLog(@"cpp: %d", charsPerPage_); 
  84.          
  85.         // 计算totalPages_ 
  86.         totalPages_ = (int)bookItem.content.length / charsPerPage_ + 1; 
  87.         NSLog(@"ttp: %d", totalPages_); 
  88.          
  89.         // 计算最后一页的字符数,防止范围溢出 
  90.         charsOfLastPage_ = textLength_ - (totalPages_ - 1) * charsPerPage_; 
  91.         NSLog(@"colp: %d", charsOfLastPage_); 
  92.          
  93.         // 分页完成 
  94.         return YES; 
  95.     } 

这样就看不到碍眼的黄色警告标志了。
重要的是,由于该方法计算文本的尺寸更为准确,所以可以使得分页后页与页之间的连贯性好了很多,而且每页的空间利用率都提高了很多,每页的文字几乎铺满了整个页面。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值