Find last visible line index in NSAttributedString's drawWithRect

纵饮孤独 提交于 2019-12-19 04:19:06

问题


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?


回答1:


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).



来源:https://stackoverflow.com/questions/28764651/find-last-visible-line-index-in-nsattributedstrings-drawwithrect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!