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?
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.
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With