Is it possible to change color of single word in UITextView and UITextField

为君一笑 提交于 2019-11-26 20:30:20

Yes you need to use NSAttributedString for that, find the RunningAppHere.

Scan through the word and find the range of your word and change its color.

EDIT:

- (IBAction)colorWord:(id)sender {
    NSMutableAttributedString * string = [[NSMutableAttributedString alloc]initWithString:self.text.text];

    NSArray *words=[self.text.text componentsSeparatedByString:@" "];

    for (NSString *word in words) {        
        if ([word hasPrefix:@"@"]) {
            NSRange range=[self.text.text rangeOfString:word];
            [string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:range];           
        }
    }
    [self.text setAttributedText:string];
}

EDIT 2 : see the screenshot

this is a swift implementation from @Anoop Vaidya answer,this function detect any word between {|myword|} , color these words in red and remove the special characters, hope this may help someone else:

 func getColoredText(text:String) -> NSMutableAttributedString{
    var string:NSMutableAttributedString = NSMutableAttributedString(string: text)
    var words:[NSString] = text.componentsSeparatedByString(" ")

    for (var word:NSString) in words {
        if (word.hasPrefix("{|") && word.hasSuffix("|}")) {
            var range:NSRange = (string.string as NSString).rangeOfString(word)
            string.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: range)
            word = word.stringByReplacingOccurrencesOfString("{|", withString: "")
            word = word.stringByReplacingOccurrencesOfString("|}", withString: "")
            string.replaceCharactersInRange(range, withString: word)
        }
    }
    return string
}

you can use it like this:

self.msgText.attributedText = self.getColoredText("i {|love|} this!")

Modified @fareed's answer for swift 2.0 and this is working (tested in a playground):

func getColoredText(text: String) -> NSMutableAttributedString {
    let string:NSMutableAttributedString = NSMutableAttributedString(string: text)
    let words:[String] = text.componentsSeparatedByString(" ")
    var w = ""

    for word in words {
        if (word.hasPrefix("{|") && word.hasSuffix("|}")) {
            let range:NSRange = (string.string as NSString).rangeOfString(word)
            string.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: range)
            w = word.stringByReplacingOccurrencesOfString("{|", withString: "")
            w = w.stringByReplacingOccurrencesOfString("|}", withString: "")
            string.replaceCharactersInRange(range, withString: w)
        }
    }
    return string
}

getColoredText("i {|love|} this!")

@fareed namrouti implementation rewritten in Swift 3

func getColoredText(text: String) -> NSMutableAttributedString {
    let string:NSMutableAttributedString = NSMutableAttributedString(string: text)
    let words:[String] = text.components(separatedBy:" ")
    var w = ""

    for word in words {
        if (word.hasPrefix("{|") && word.hasSuffix("|}")) {
            let range:NSRange = (string.string as NSString).range(of: word)
            string.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: range)
            w = word.replacingOccurrences(of: "{|", with: "")
            w = w.replacingOccurrences(of:"|}", with: "")
            string.replaceCharacters(in: range, with: w)
        }
    }
    return string
}
-(void)colorHashtag
{
NSMutableAttributedString * string = [[NSMutableAttributedString alloc]initWithString:textView.text];

NSString *str = textView.text;
NSError *error = nil;

//I Use regex to detect the pattern I want to change color
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"#(\\w+)" options:0 error:&error];



NSArray *matches = [regex matchesInString:textView.text options:0 range:NSMakeRange(0, textView.text.length)];

for (NSTextCheckingResult *match in matches) {
    NSRange wordRange = [match rangeAtIndex:0];
    [string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:wordRange]; 
}

[textView setAttributedText:string];
}

To expound on Jamal Kharrat's answer, and to rewrite it into SWIFT, here is how to do it in a UITextView:

  1. Set your UITextView to "Attributed" in the storyboard
  2. Right-click & drag to ViewController icon at the top of the view (XC 6), and set the delegate
  3. Create an IBOutlet for your UITextView (we'll call it "textView")
  4. Make your class conform to UITextViewDelegate

Here is Jamal's function written in SWIFT:

func colorHastag(){
    var string:NSMutableAttributedString = NSMutableAttributedString(string: textView.text)
    var str:NSString = textView.text
    var error:NSError?
    var match:NSTextCheckingResult?

    var regEx:NSRegularExpression = NSRegularExpression(pattern: "#(\\w+)", options: nil, error: &error)!
    var matches:NSArray = regEx.matchesInString(textView.text, options: nil, range: NSMakeRange(0, countElements(textView.text)))

    for (match) in matches {
        var wordRange:NSRange = match.rangeAtIndex(0)
        string.addAttribute(NSForegroundColorAttributeName, value: UIColor.blueColor(), range: wordRange)
    }

    textView.attributedText = string
}

Now, you'll need to call this function. To do this every time the user types a character, you can use:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    self.colorHastag()
    return true
}

You'll notice that I changed the color to blue. You can set it to any color. Also, you can strip out the :Type for every variable. You'll also want to set becomeFirstResponder() and also handle resignFirstResponder() for a good user experience. You could also throw in some error handling. This will only convert hashtags to blue. You will need to modify or add a regEx to handle the @.

The solution is this:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];

NSArray *words=[txtDescription.text componentsSeparatedByString:@" "];

for (NSString *word in words)
{
    if ([word hasPrefix:@"@"] || [word hasPrefix:@"#"])
    {
        [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ ", word]
                                                                                 attributes:@{NSFontAttributeName: [UIFont fontWithName:FONT_LIGHT size:15],
                                                                                              NSForegroundColorAttributeName: [ImageToolbox colorWithHexString:@"f64d5a"]}]];
    }
    else // normal text
    {
        [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ ", word]
                                                                                 attributes:@{NSFontAttributeName: [UIFont fontWithName:FONT_LIGHT size:15],
                                                                                              NSForegroundColorAttributeName: [ImageToolbox colorWithHexString:@"3C2023"]}]];
    }
}

if([[attributedString string] hasSuffix:@" "]) // loose the last space
{
    NSRange lastCharRange;
    lastCharRange.location=0;
    lastCharRange.length=[attributedString string].length-1;

    attributedString=[[NSMutableAttributedString alloc] initWithAttributedString:[attributedString attributedSubstringFromRange:lastCharRange]];
}

[txtDescription setAttributedText:attributedString];

Yes it is possible. However I have found it can be a headache trying to use NSMutableAttributesString with a Swift Range. The code below will get you around having to use the Range class and return you an attributed string with the words highlighted a different color.

extension String {
    func getRanges(of string: String) -> [NSRange] {
        var ranges:[NSRange] = []
        if contains(string) {
            let words = self.components(separatedBy: " ")
            var position:Int = 0
            for word in words {
                if word.lowercased() == string.lowercased() {
                    let startIndex = position
                    let endIndex = word.characters.count
                    let range = NSMakeRange(startIndex, endIndex)
                    ranges.append(range)
                }
                position += (word.characters.count + 1) // +1 for space
            }
        }
        return ranges
    }
    func highlight(_ words: [String], this color: UIColor) -> NSMutableAttributedString {
        let attributedString = NSMutableAttributedString(string: self)
        for word in words {
            let ranges = getRanges(of: word)
            for range in ranges {
                attributedString.addAttributes([NSForegroundColorAttributeName: color], range: range)
            }
        }
        return attributedString
    }
}

Usage:

// The strings you're interested in
let string = "The dog ran after the cat"
let words = ["the", "ran"]

// Highlight words and get back attributed string
let attributedString = string.highlight(words, this: .yellow)

// Set attributed string
textView.attributedText = attributedString
Andrei Boleac

After setting an attributedtext you can set typingAttributes of UITextView with the values you want for you input field.

NSDictionary *attribs = @{
    NSForegroundColorAttributeName:[UIColor colorWithHex:kUsernameColor],
    NSFontAttributeName:[UIFont robotoRegularWithSize:40]
};
self.textView.typingAttributes = attribs;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!