Reputation: 26526
My UITextView delegate is logging the caret position using the following:
- (void)textViewDidBeginEditing:(UITextView *)textView
{
CGPoint cursorPosition = [textView caretRectForPosition:textView.selectedTextRange.start].origin;
NSLog(@"cursor: %@", NSStringFromCGPoint(cursorPosition));
}
But the reported position is always inaccurate. Specifically, it reports the previous cursor position - for example, if I click once inside the text view at position (x,y) then outside, then back inside at (x2,y2), on the second click the (x,y) coordinates are logged.
In fact, the selectedTextRange is the issue - the previous range is reported.
What am I missing? I don't see another delegate method I can use instead.
Upvotes: 7
Views: 3033
Reputation: 10204
I had the same problem, but with UIKeyboardWillShowNotification
. Adding a small delay helped in my case:
func keyboardWillAppear(notification: NSNotification!) {
dispatch_after_delay(0.01) {
if textView.selectedTextRange {
// at this point range is correct
}
}
}
func dispatch_after_delay(delay:NSTimeInterval, queue: dispatch_queue_t = dispatch_get_main_queue(), block: dispatch_block_t) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), queue, block)
}
Upvotes: 1
Reputation: 877
Actually, I found another solution to this.
You can use the UIKeyboardDidShowNotification
to get the current selectedTextRange, and not the previous selectedTextRange. I hope it helps!
Upvotes: 1
Reputation: 2417
Value of selectedTextRange will be older only as the editing has just began, it has not changed yet. As you are calculating the cursorPostion with selected text, old values will lead to old position. So we need to calculate the new position inside a different delegate which reports after the selection changes. You will get correct readings with below mentioned code. Hope it helps
-(void)textViewDidChangeSelection:(UITextView *)textView
{
CGPoint cursorPosition = [textView caretRectForPosition:textView.selectedTextRange.start].origin;
NSLog(@"cursor start: %@", NSStringFromCGPoint(cursorPosition));
}
Upvotes: 5
Reputation: 26526
It's pretty gross but one solution is to introduce a short delay before reading calling the method:
UITextView *textView = note.object;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGPoint cursorPosition = [textView caretRectForPosition:textView.selectedTextRange.start].origin;
NSLog(@"cursor: %@", NSStringFromCGPoint(cursorPosition));
});
Upvotes: 4