5

I'm working on an autocompletion component and I have one problem that I would like to solve in some easy way.

I want to support edits to autocompleted text, for example:

 blablabl @usertag blablabl

If user goes back and edits @usertag string, I would like to start autocompletion when it's edited.

Question is, how to get currently edited word from textfield. I thought about taking cursor position, seperate nsstring to word by " " (space) and count letters from first word to cursor position.

Is there any easier way for doing that?

A Salcedo
  • 6,378
  • 8
  • 31
  • 42
Grzegorz Krukowski
  • 18,081
  • 5
  • 50
  • 71

4 Answers4

8

Ok I found a way to do it quite easily. Maybe someone will find it useful:

UITextRange* selectedRange = [textField selectedTextRange];
NSInteger cursorOffset = [textField offsetFromPosition:0 toPosition:selectedRange.start];
NSString* text = textField.text;
NSString* substring = [text substringToIndex:cursorOffset];
NSString* editedWord = [[substring componentsSeparatedByString:@" "] lastObject];
Grzegorz Krukowski
  • 18,081
  • 5
  • 50
  • 71
5

Swift 4 Solution

   func getCurrentEditingWord() ->String? {
        let selectedRange: UITextRange? = self.textView.selectedTextRange
        var cursorOffset: Int? = nil
        if let aStart = selectedRange?.start {
            cursorOffset = self.textView.offset(from: self.textView.beginningOfDocument, to: aStart)
        }
        let text = self.textView.text
        let substring = (text as NSString?)?.substring(to: cursorOffset!)
        let editedWord = substring?.components(separatedBy: " ").last
        return editedWord
    }
Prashant Tukadiya
  • 15,838
  • 4
  • 62
  • 98
3

Here is a solution for the efficiency nerds. Written in Swift 4.2. I'm claiming that is is more efficient because other answers are calling the String method String.component which unnecessarily converts the entire substring to an array. Also those solutions are always grabbing words before the cursor which may not necessarily be the current word.

extension UITextView {
    /// Returns the current word that the cursor is at.
    func currentWord() -> String {
        guard let cursorRange = self.selectedTextRange else { return "" }
        func getRange(from position: UITextPosition, offset: Int) -> UITextRange? {
            guard let newPosition = self.position(from: position, offset: offset) else { return nil }
            return self.textRange(from: newPosition, to: position)
        }
    
        var wordStartPosition: UITextPosition = self.beginningOfDocument
        var wordEndPosition: UITextPosition = self.endOfDocument
    
        var position = cursorRange.start
    
        while let range = getRange(from: position, offset: -1), let text = self.text(in: range) {
            if text == " " || text == "\n" {
                wordStartPosition = range.end
                break
            }
            position = range.start
        }
    
        position = cursorRange.start
    
        while let range = getRange(from: position, offset: 1), let text = self.text(in: range) {
            if text == " " || text == "\n" {
                wordEndPosition = range.start
                break
            }
            position = range.end
        }
    
        guard let wordRange = self.textRange(from: wordStartPosition, to: wordEndPosition) else { return "" }
    
        return self.text(in: wordRange) ?? ""
    }
}
Woody Jean-louis
  • 475
  • 6
  • 12
0

Have you tried using UITextFieldDelegate available methods? If access to the word as you edit it is what you want, you can simply use the -textField:shouldChangeCharactersInRange:replacementString: Inside this method you have access to the string as it's entered, and you can also do any string manipulation here for every new character entered.

A Salcedo
  • 6,378
  • 8
  • 31
  • 42
  • Not really - I want to show UITableView and allow user to select one of autocopmpletion items available. As reference: http://www.appscout.com/images/twitteriphone-auto.jpg – Grzegorz Krukowski Mar 19 '14 at 14:11
  • You could use a popover for the textfield that is launched when changing characters (the method previously mentioned). Only launch it if it is not present at the time, and modify it when the characters are entered. But the design part is up to you. All of this can be done with the appropriate protocol implementations. – A Salcedo Mar 19 '14 at 14:14
  • Yes I have it working - all I asking is how to get a "WORD" out of the string which is in UITextField - to pass it to my autocompletion component. Currently it works fine, as long as @ and # are last words in text – Grzegorz Krukowski Mar 19 '14 at 14:16