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 } } }
var myInstanceOfAClass : AClass = AClass()orvar myInstanceOfAClass : AClass = AClass(stuffTheClassNeeds: StuffIGiveToTheClass)Look closely at the code in my answer. You need all parts.myInstanceOfAClass.myClassFunction()ormyInstanceOfAClass.myClassFunction(stuffTheFunctionNeeds: StuffIGiveToTheFunction)