Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITextView firstRectForRange not working when there's new line characters in the mix

I'm using this method for converting a NSRange to a CGRect as it relates to a UITextView:

- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView
{
    UITextPosition *beginning = textView.beginningOfDocument;
    UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [textView positionFromPosition:beginning offset:range.location+range.length];
    UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
    CGRect rect = [textView firstRectForRange:textRange];
    return rect;
}

This question's answer has someone asking the same question as me. The above method works great for this:

this is a great text field yes it is findthistoken

Not so great like this:

this is a great one
(new line)
(new line)
findthistoken

It seems to simply ignore the fact that there are 2 new lines characters? :/

How do I make it work with new line characters?

like image 927
Mike S Avatar asked Oct 22 '25 05:10

Mike S


2 Answers

You can force self.textView to ensure the layout of textView immediately with

 [self.textView.layoutManager ensureLayoutForTextContainer:self.textView.textContainer];

Placing that before your frameOfTextRange: call will gives you right rect.

like image 184
Arshad Avatar answered Oct 23 '25 19:10

Arshad


For swift 5

In the case of a long textView with couple line breaks and where you have to scroll down, I've found that the problem still persisted even after adding the following line of code, before firstRectForRange:

[self.textView.layoutManager ensureLayoutForTextContainer:self.textView.textContainer];

firstRectForRange still returned a wrong frame, but a solution to this was to ensure layout after each scroll in scrollViewDidScroll.

For swift 5:

extension yourController {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        textView.layoutManager.ensureLayout(for:textView.textContainer)
    }
}
like image 27
Abv Avatar answered Oct 23 '25 20:10

Abv