I'm trying to display an UIPopoverController
from the rect of a selected text in an UITextView
, How can I get the selected text CGRect
?
Thanks!
I'm trying to display an UIPopoverController
from the rect of a selected text in an UITextView
, How can I get the selected text CGRect
?
Thanks!
I think [UITextInput selectedTextRange]
and [UITextInput caretRectForPosition:]
is what you are looking for.
[UITextInput selectedTextRange]
returns the selected range in character
[UITextInput caretRectForPosition:]
returns the CGRect
of the character range in this input.
UITextView
conforms to UITextInput
(since iOS 5), so you can use these methods for your UITextView
instance.
It is going to be something like this.
UITextRange * selectionRange = [textView selectedTextRange];
CGRect selectionStartRect = [textView caretRectForPosition:selectionRange.start];
CGRect selectionEndRect = [textView caretRectForPosition:selectionRange.end];
CGPoint selectionCenterPoint = (CGPoint){(selectionStartRect.origin.x + selectionEndRect.origin.x)/2,(selectionStartRect.origin.y + selectionStartRect.size.height / 2)};
EDIT : Since the sample code became a little hard to get, I added an image for complementing.
There are some situations where barley's answer won't actually give the center of the selection. For example:
In this case you can see the Copy/Paste menu is displaying in the center of the selection, which spans the entire width of the text field. But calculating the center of the two caret rects would give a position much further to the right.
You can get a more precise result using selectionRectsForRange:
UITextRange *selectionRange = [textView selectedTextRange];
NSArray *selectionRects = [self.textView selectionRectsForRange:selectionRange];
CGRect completeRect = CGRectNull;
for (UITextSelectionRect *selectionRect in selectionRects) {
if (CGRectIsNull(completeRect)) {
completeRect = selectionRect.rect;
} else completeRect = CGRectUnion(completeRect,selectionRect.rect);
}
It's also worth clarifying that if you're still supporting iOS 4 and using either of these answers, you'll need to make sure these methods are supported before calling them: if ([textView respondsToSelector:@selector(selectedTextRange)]) { …
Swift 5 version:
if let selectionRect = textView.selectedTextRange {
let selectionRects = textView.selectionRects(for: selectionRect)
var completeRect = CGRect.null
for rect in selectionRects {
if (completeRect.isNull) {
completeRect = rect.rect
} else {
completeRect = rect.rect.union(completeRect)
}
}
}