I am creating a pdf from user provided text, however I have an issue when the text is too big for the page, I have to calculate where the text would be cut off so I can move the next chunk to the next page. I use this code to draw the attributed text:
CGRect rect = CGRectFromString(elementInfo[@"rect"]);
NSString *text = elementInfo[@"text"];
NSDictionary *attributes = elementInfo[@"attributes"];
NSAttributedString *attString = [[NSAttributedString alloc] initWithString:text attributes:attributes];
[attString drawWithRect:rect options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine context:nil];
How can I get the place where the "last visible line" is?
What this solution does is it checks if your text will fit within a UITextView
with the given frame and font, and if not, it removes the last word from the string and checks again if it fits. It continues this process until it fits in the given frame. Once it gets within the given size, the index where the string should be split is returned.
- (NSUInteger)pageSplitIndexForString:(NSString *)string
inFrame:(CGRect)frame
withFont:(UIFont *)font
{
CGFloat fixedWidth = frame.size.width;
UITextView *textView = [[UITextView alloc] initWithFrame:frame];
textView.text = string;
textView.font = font;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
while (newFrame.size.height > frame.size.height) {
textView.text = [self removeLastWord:textView.text];
newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
}
NSLog(@"Page one text: %@", textView.text);
NSLog(@"Page two text: %@", [string substringFromIndex:textView.text.length]);
return textView.text.length;
}
Method to remove last word:
- (NSString *)removeLastWord:(NSString *)str
{
__block NSRange lastWordRange = NSMakeRange([str length], 0);
NSStringEnumerationOptions opts = NSStringEnumerationByWords | NSStringEnumerationReverse | NSStringEnumerationSubstringNotRequired;
[str enumerateSubstringsInRange:NSMakeRange(0, [str length]) options:opts usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
lastWordRange = substringRange;
*stop = YES;
}];
return [str substringToIndex:lastWordRange.location];
}
To use this "pageSplit
" method, you would call it and check the returned index against the length of the supplied string. If the returned index is less than the string's length, you know you'll need to split into a second page.
To give some credit where credit is due, I borrowed code from a couple other SO answers (How do I size a UITextView to its content? and Getting the last word of an NSString) to come up with my solution.
Per your comments, I've edited my answer to have a method where you can send the particulars and get back the index within the string you want to split. You supply the string, container size, and font and it will let you know where the page split will occur (index within the string).