制作 iPhone 电子书时,如果把大段文字放在 UITextView 或 UILabel 里显示,是不能分页的,阅读时就像再看一大卷滚不到头的纸带,用户体验很差。下面这段代码可以实现 UILabel 尺寸固定,根据文本内容和字体动态分页显示,电子书方面的应用应该非常有用。
1 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 2 - (void)viewDidLoad { 3 [super viewDidLoad]; 4 5 // 6 totalPages = 0; 7 currentPage = 0; 8 9 // 10 textLabel.numberOfLines = 0; 11 12 // 13 if (!text) { 14 // 从文件里加载文本串 15 [self loadString]; 16 17 // 计算文本串的大小尺寸 18 CGSize totalTextSize = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE_MAX] 19 constrainedToSize:CGSizeMake(textLabel.frame.size.width, CGFLOAT_MAX) 20 lineBreakMode:UILineBreakModeWordWrap]; 21 22 // 如果一页就能显示完,直接显示所有文本串即可。 23 if (totalTextSize.height < textLabel.frame.size.height) { 24 textLabel.text = text; 25 } 26 else { 27 // 计算理想状态下的页面数量和每页所显示的字符数量,只是拿来作为参考值用而已! 28 NSUInteger textLength = [text length]; 29 referTotalPages = (int)totalTextSize.height/(int)textLabel.frame.size.height+1; 30 referCharatersPerPage = textLength/referTotalPages; 31 32 // 申请最终保存页面NSRange信息的数组缓冲区 33 int maxPages = referTotalPages; 34 rangeOfPages = (NSRange *)malloc(referTotalPages*sizeof(NSRange)); 35 memset(rangeOfPages, 0x0, referTotalPages*sizeof(NSRange)); 36 37 // 页面索引 38 int page = 0; 39 40 for (NSUInteger location = 0; location < textLength; ) { 41 // 先计算临界点(尺寸刚刚超过UILabel尺寸时的文本串) 42 NSRange range = NSMakeRange(location, referCharatersPerPage); 43 44 // reach end of text ? 45 NSString *pageText; 46 CGSize pageTextSize; 47 48 while (range.location + range.length < textLength) { 49 pageText = [text substringWithRange:range]; 50 51 pageTextSize = [pageText sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE_MAX] 52 constrainedToSize:CGSizeMake(textLabel.frame.size.width, CGFLOAT_MAX) 53 lineBreakMode:UILineBreakModeWordWrap]; 54 55 if (pageTextSize.height > textLabel.frame.size.height) { 56 break; 57 } 58 else { 59 range.length += referCharatersPerPage; 60 } 61 } 62 63 if (range.location + range.length >= textLength) { 64 range.length = textLength - range.location; 65 } 66 67 // 然后一个个缩短字符串的长度,当缩短后的字符串尺寸小于textLabel的尺寸时即为满足 68 while (range.length > 0) { 69 pageText = [text substringWithRange:range]; 70 71 pageTextSize = [pageText sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE_MAX] 72 constrainedToSize:CGSizeMake(textLabel.frame.size.width, CGFLOAT_MAX) 73 lineBreakMode:UILineBreakModeWordWrap]; 74 75 if (pageTextSize.height <= textLabel.frame.size.height) { 76 range.length = [pageText length]; 77 break; 78 } 79 else { 80 range.length -= 2; 81 } 82 } 83 84 // 得到一个页面的显示范围 85 if (page >= maxPages) { 86 maxPages += 10; 87 rangeOfPages = (NSRange *)realloc(rangeOfPages, maxPages*sizeof(NSRange)); 88 } 89 rangeOfPages[page++] = range; 90 91 // 更新游标 92 location += range.length; 93 } 94 95 // 获取最终页面数量 96 totalPages = page; 97 98 // 更新UILabel内容 99 textLabel.text = [text substringWithRange:rangeOfPages[currentPage]]; 100 } 101 } 102 103 // 显示当前页面进度信息,格式为:"8/100" 104 pageInfoLabel.text = [NSString stringWithFormat:@"%d/%d", currentPage+1, totalPages]; 105 }
1 // 上一页 2 - (IBAction)actionPrevious:(id)sender { 3 if (currentPage > 0) { 4 currentPage--; 5 6 NSRange range = rangeOfPages[currentPage]; 7 NSString *pageText = [text substringWithRange:range]; 8 9 textLabel.text = pageText; 10 11 // 12 pageInfoLabel.text = [NSString stringWithFormat:@"%d/%d", currentPage+1, totalPages]; 13 } 14 }
1 // 下一页 2 - (IBAction)actionNext:(id)sender { 3 if (currentPage < totalPages-1) { 4 currentPage++; 5 6 NSRange range = rangeOfPages[currentPage]; 7 NSString *pageText = [text substringWithRange:range]; 8 9 textLabel.text = pageText; 10 11 // 12 pageInfoLabel.text = [NSString stringWithFormat:@"%d/%d", currentPage+1, totalPages]; 13 } 14 }