Making a text view respond to text typed by the user

5 Solutions Collect From Internet About “Making a text view respond to text typed by the user”

You need three things :

  • In the interface builder you need to use one of the delegate methods. I think “editingChanged” is the best here. Drag from the textfield with “ctrl” to you document.

  • You need a way to go over the string from textfield and detect words.

    componentsSeparatedByCharactersInSet

  • You need a way to style one word in a sentence.

    NSMutableAttributedString

Also interesting : how to separate a string without removing the delimiter

Part of the code (throw this in a playground) :

This will find all the words to change, but remove separators. More work is needed to complete the code.

var strSeperator : NSCharacterSet = NSCharacterSet(charactersInString: ",.:;?! ")

var strArray = str.componentsSeparatedByCharactersInSet(strSeperator)

var styledText = NSMutableAttributedString()

for i in 0..<strArray.count {

    let currentWord = strArray[i]
    var currentBoolFoundInControl : Bool = false

    for iB in 0..<colorTheseStrings.count {

        let controlWord = colorTheseStrings[iB]

        if controlWord == currentWord {
            currentBoolFoundInControl = true
            // add to mutable attributed string in a color
        }

    }

    var attrString1 = NSMutableAttributedString(string: "\(strArray[i]) ")

    if currentBoolFoundInControl == true {

        var range = (strArray[i] as NSString).rangeOfString(strArray[i])
        if strArray[i] == "red" {
            attrString1.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.5, green: 0.0, blue: 0.0, alpha: 1.0), range: range)
        } else if strArray[i] == "blue" {
            attrString1.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.0, green: 0.0, blue: 0.5, alpha: 1.0), range: range)

        }
    }

    styledText.appendAttributedString(attrString1)
}

myTextField.attributedText = styledText

One More Way:

download it here

I think this way is the most robust and the coolest and the most efficient.
Code could be cleaned up a bit and could use a bit more style/flair. This does have trouble with things like the “sky blue” because it will find “blue” first and replace it. But I had to leave some room for improvement. ๐Ÿ˜‰

And I couldn’t help myself, so I fixed that last issue.

And again, I fixed, my fix. More efficient and actually correct now.

The first part is the HighLighter class, drop this in a separate document.

// text hightlighter

class SyntaxGroup {

    var wordCollection : [String] = []
    var type : String = ""
    var color : UIColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

    init(wordCollection_I : [String], type_I : String, color_I: UIColor) {

        wordCollection = wordCollection_I
        type = type_I
        color = color_I

    }
}

class SyntaxDictionairy {

    var collections : [SyntaxGroup] = []

}

class SyntaxRange {

    var range : NSRange
    var color : UIColor

    init (color_I : UIColor, range_I : NSRange) {
        color = color_I
        range = range_I
    }

}

class HighLighter {

    var ranges : [SyntaxRange] = []
    var baseString : NSMutableString = NSMutableString()
    var highlightedString : NSMutableAttributedString = NSMutableAttributedString()
    var syntaxDictionairy : SyntaxDictionairy

    init (syntaxDictionairy_I : SyntaxDictionairy) {

        syntaxDictionairy = syntaxDictionairy_I

    }

    func run(string : String?, completion: (finished: Bool) -> Void) {

        ranges = [] // reset the ranges, else it crashes when you change a previous part of the text
        highlightedString = NSMutableAttributedString() // make sure all strings start fresh
        baseString = NSMutableString() // make sure all strings start fresh

        // multi threading to prevent locking up the interface with large libraries.
        let qualityOfServiceClass = QOS_CLASS_DEFAULT
        let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
        dispatch_async(backgroundQueue) { () -> Void in

            if string != nil && string != "" {

                self.highlightedString = NSMutableAttributedString(string: string!)

                for i in 0..<self.syntaxDictionairy.collections.count {

                    for iB in 0..<self.syntaxDictionairy.collections[i].wordCollection.count {

                        let currentWordToCheck = self.syntaxDictionairy.collections[i].wordCollection[iB]
                        self.baseString = NSMutableString(string: string!)

                        while self.baseString.containsString(self.syntaxDictionairy.collections[i].wordCollection[iB]) {

                            let nsRange = (self.baseString as NSString).rangeOfString(currentWordToCheck)
                            let newSyntaxRange = SyntaxRange(color_I: self.syntaxDictionairy.collections[i].color, range_I: nsRange)
                            self.ranges.append(newSyntaxRange)

                            var replaceString = ""
                            for _ in 0..<nsRange.length {
                                replaceString += "ยง" // secret unallowed character
                            }
                            self.baseString.replaceCharactersInRange(nsRange, withString: replaceString)
                        }
                    }
                }
                for i in 0..<self.ranges.count {

                    self.highlightedString.addAttribute(NSForegroundColorAttributeName, value: self.ranges[i].color, range: self.ranges[i].range)

                }
            }

            dispatch_sync(dispatch_get_main_queue()) { () -> Void in

                completion(finished: true)
            }

        }
    }
}

In the ViewController :
This is the code you will use with the UITextfield.
First create an instance of the highlighter and set up your dictionary of words and corresponding colours. Then start the run function when needed.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var myTextfield: UITextField!

    var syntaxHighLighter : HighLighter! // declare highlighter

    override func viewDidLoad() {
        super.viewDidLoad()
        setUpHighLighter()
    }
    // this is just a little function to put the set up for the highlighter outside of viewDidLoad()
    func setUpHighLighter() {

        // build a dict of words to highlight
        let redColor = UIColor(red: 0.5, green: 0.0, blue: 0.0, alpha: 1.0)
        let blueColor = UIColor(red: 0.0, green: 0.0, blue: 0.5, alpha: 1.0)
        let greenColor = UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0)

        let redGroup = SyntaxGroup(wordCollection_I: ["red","bordeaux"], type_I: "Color", color_I: redColor)
        let blueGroup = SyntaxGroup(wordCollection_I: ["coralblue","blue","skyblue","azur"], type_I: "Color", color_I: blueColor)
        let greenGroup = SyntaxGroup(wordCollection_I: ["green"], type_I: "Color", color_I: greenColor)

        let dictionairy : SyntaxDictionairy = SyntaxDictionairy()
        dictionairy.collections.append(blueGroup)
        dictionairy.collections.append(greenGroup)
        dictionairy.collections.append(redGroup)

        syntaxHighLighter = HighLighter(syntaxDictionairy_I: dictionairy)

    }
    // this is where the magic happens, place the code from inside the editingChanged inside your function that responds to text changes.
    @IBAction func editingChanged(sender: UITextField) {

        syntaxHighLighter.run(myTextfield.text) { (finished) -> Void in
            self.myTextfield.attributedText = self.syntaxHighLighter.highlightedString
        }
    }
}
textField.addTarget(self, action: "textFieldDidChange:",forControlEvents: UIControlEvents.EditingChanged)

func textFieldDidChange(textField: UITextField) {
//your code

var main_string = textField.text
var string_to_color = "red"

var range = (main_string as NSString).rangeOfString(string_to_color)

var attributedString = NSMutableAttributedString(string:main_string)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor() , range: range)

}

maybe you can implement the Text View Delegate to detect when the user finish typing, ask in a conditional if the written text is what you want, and in the positive case do something(change colour).
Here you have some documentation https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextViewDelegate_Protocol/
You can try implementing something like this:

let text: UITextView? //this must be binded with the storyboard ui

//MARK UITextViewDelegate

func textViewDidChange(_ textView: UITextView){
     if (textView.text == "bla"){
         textView.colour == UIColour(Red)
     }
}

This code is just a schema. Read the docs and check the syntaxis. Hope it helps!!

Fede

You have to use attributedText
in the UITextView delegate method

- (void)textViewDidChange:(UITextView *)textView

this will solve your problem.

I think what you should do is this (Correct me if I’m wrong because I don’t have Xcode to testit on this computer but this should work). If that doesn’t work do what Fawad Masud and add this to view did load…

 yourTextView.addTarget(self, action: "textViewDidChange:",forControlEvents: UIControlEvents.EditingChanged)

override func viewDidLoad() {
    super.viewDidLoad()
    yourTextView.delegate = self //Basically makes the function below applicable to this textview
}

func textViewDidChange(textView: UITextView) { //Every time text changes this code is run
   var textViewText = yourTextView.text as NSString!

if textViewText.containsString("red") {
      textViewText.textColor = UIColor.redColor()

   }
}