3

I have an UITextView which can have multiple lines. All I'm interested in is the position of the cursor on a certain line (where it doesn't matter whether first, second, third line etc.).

I've been logging UITextRange.start which gives me exactly what I need, namely the offset property:

cp <UITextPositionImpl: 0x6e93260> <<WebVisiblePosition: 0x6e92d00>(offset=5, context=([d|], [u+0064|u+0000])>

My question is how I get the offset=5 into a simply integer?

Here is my code:

UITextRange *caretPositionRange = textView.selectedTextRange;
NSLog(@"cp %@", caretPositionRange.start);

All I need would be something like int cp = caretPositionRange.start.offset which doesn't work.


edit:

to clarify, I'm particularly interested in the cursor position of each line, not the entire TextView. So this won't really work:

UITextRange *caretPositionRange = tv.selectedTextRange;
    int caretPosition = [tv offsetFromPosition:tv.beginningOfDocument
                            toPosition:caretPositionRange.start];

as this would give me a different position for each line.


edit 2:

the answer below given by Jesse works really well. First time around, I got an EXC_BAD_EXCESS as I didn't check if startOfLine = nil, so keep in mind checking if it's not nil.

Jesse Rusak
  • 56,530
  • 12
  • 101
  • 102
n.evermind
  • 11,944
  • 19
  • 78
  • 122

1 Answers1

3

You'll need to ask the UITextView via its UITextInput methods. Something like this:

UITextPosition *pos = caretPositionRange.start;
id<UITextInputTokenizer> tokenizer = [textView tokenizer];
UITextPosition *startOfLine = [tokenizer positionFromPosition:pos 
                                                   toBoundary:UITextGranularityLine
                                                 inDirection:UITextStorageDirectionBackward];
if (startOfLine != nil) {
    // based on some experiments, startOfLine may be nil for, eg, empty text views
    // the next line crashes if you pass nil, so we check first
    NSUInteger offset = [textView offsetFromPosition:startOfLine
                                          toPosition:pos];
}
Jesse Rusak
  • 56,530
  • 12
  • 101
  • 102
  • This won't work as I'm not interested in the position from the beginningOfDocument, but rather the beginning of the line. Offset will always give me the exact value. If I do what you suggest, I will get increasing values, e.g. I won't always get offset=5 if the cursor is on the fifth position from the beginning of a line. – n.evermind Jun 10 '12 at 19:19
  • Oh, wow. I completely mis-read your question, sorry. One sec. – Jesse Rusak Jun 10 '12 at 19:20
  • OK, that should do it now. You might want to use UITextLayoutDirectionLeft instead depending on how it should handle right-to-left text. – Jesse Rusak Jun 10 '12 at 19:24
  • Thanks a lot. It should read offsetFromPosition instead of positionFromPosition, right? Just trying this out. – n.evermind Jun 10 '12 at 19:27
  • Sorry, I'm a bit confused, there is only positionFromPosition:inDirection:offset: and positionFromPosition:offset: ... if I'm not missing something obvious here... – n.evermind Jun 10 '12 at 19:28
  • You're welcome. It should be positionFromPosition; you're computing the start of line first. – Jesse Rusak Jun 10 '12 at 19:29
  • 1
    Sorry; I fixed a small bug. Try now. – Jesse Rusak Jun 10 '12 at 19:29
  • Sorry to be such a pain, but now I get a EXC_BAD_ACCESS for the last line of code you've suggested. No log output... this is quite complex. – n.evermind Jun 10 '12 at 19:34
  • 1
    let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/12359/discussion-between-jesse-rusak-and-n-evermind) – Jesse Rusak Jun 10 '12 at 19:35