1

I'm trying to make a "tagging window" much like the one used in Facebook where you type "@" and it make suggestions among your friends on which one to tag. I'd like this feature in my app, but I can't for the life of me figure out how to get the currently typed word in order to filter suggestions.

I use an UITextView and I've been looking at this post https://stackoverflow.com/a/27380612/4148782

but I have issues translating this to Swift 3, and even so the comments suggests that this isn't solved anyway.

So the functionality I'm after is:

  • User starts typing in a UITextView and if the word begins with a "@" I'd like to extract the word.
  • I'd like to replace the word with a certain input as well. Let's say the user types @abc and I filter a suggestion which states "abcdef", then I want to be able to replace the @abc in the UITextView with "abcdef".

Note that I want the word currently getting typed and not the most recent typed word.

Community
  • 1
  • 1
ClockWise
  • 1,509
  • 15
  • 32
  • You know, there's a site to translate from obj-C to swift called [https://objectivec2swift.com/](https://objectivec2swift.com/) – Tj3n Aug 16 '16 at 08:38
  • Cool, had no idea! Got it working without that site though, thanks. Will use for future reference. – ClockWise Aug 16 '16 at 08:42

3 Answers3

5

This works for me.

extension UITextView {

var currentWord : String? {

    let beginning = beginningOfDocument

    if let start = position(from: beginning, offset: selectedRange.location),
        let end = position(from: start, offset: selectedRange.length) {

        let textRange = tokenizer.rangeEnclosingPosition(end, with: .word, inDirection: 1)

        if let textRange = textRange {
            return text(in: textRange)
        }
    }
    return nil
   }
}
Vinayak Parmar
  • 608
  • 10
  • 18
1

As usual I spent a fair amount of time trying to get this to work, and minutes after I posted the question I got it working. So here's the code I used, but I have deprecated call for the let myRange

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    let myRange = Range<String.Index>(start: textView.text.startIndex, end: textView.text.startIndex.advancedBy(range.location))
    var subString = textView.text.substringWithRange(myRange)
    subString += text

    let wordArray = subString.componentsSeparatedByString(" ")
    if let wordTyped = wordArray.last {
        currentWord = wordTyped
        print("word typed: " + wordTyped)
    }

    return true
}
ClockWise
  • 1,509
  • 15
  • 32
0

Swift 4:

This solution worked for me inside the method func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool of UITextViewDelegate.

  func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        guard let textFieldText = textView.text,
              let rangeOfTextToReplace = Range(range, in: textFieldText) else {
                return false
        }

        let currentText = textFieldText.replacingCharacters(in: rangeOfTextToReplace, with: text)
    
        return count <= 150
    }