Sibling Thor
Sibling Thor

Reputation: 57

Adding color to a word in string using NSMutableAttributedString

I am trying to add color to 2 words in a string. This is the code I am using:

        var HighScore:Int = 0
        var CurrentScore:Int = 0

        let stringOne = "You have managed to score \(CurrentScore). Current record is \(self.HighScore). Play again and give it another try!"
        let stringTwo = "\(CurrentScore)"
        let stringThree = "\(HighScore)"

        let range1 = (stringOne as NSString).range(of: stringTwo)
        let range2 = (stringOne as NSString).range(of: stringThree)

        let attributedText = NSMutableAttributedString.init(string: stringOne)

        attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.init(netHex: 0x00b4ff) , range: range1)
        attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.init(netHex: 0x00b4ff) , range: range2)

        gameOverDescriptionLabel.attributedText = attributedText

The problem I have is that if CurrentScore and HighScore is the same(ex: 2 & 2) the color on the range2 still stays white, but if they are not equal(2 & 1 or 1 & 2) both gets the color I have choosen.

Any suggestions?

Upvotes: 0

Views: 596

Answers (4)

Rohan Dave
Rohan Dave

Reputation: 261

//MARK: forgroundColor

open var foregroundColor: UIColor? {
    didSet {
        textAttributes[NSForegroundColorAttributeName] = foregroundColor
        self.attributedText = NSAttributedString(string: self.text, attributes: textAttributes)
    }
}

//MARK: backgroundColor
open var textBackgroundColor: UIColor? {
    didSet {
        textAttributes[NSBackgroundColorAttributeName] = textBackgroundColor
        self.attributedText = NSAttributedString(string: self.text, attributes: textAttributes)
    }
}

Upvotes: 0

Erik Auranaune
Erik Auranaune

Reputation: 1414

Add this to the top or bottom of your .swift file:

extension NSMutableAttributedString {
    func bold(_ text:String) -> NSMutableAttributedString {
        let attrs:[String:AnyObject] = [NSForegroundColorAttributeName: UIColor.init(netHex: 0x00b4ff)]
        let boldString = NSMutableAttributedString(string:"\(text)", attributes:attrs)
        self.append(boldString)
        return self
    }

    func normal(_ text:String)->NSMutableAttributedString {
        let normal =  NSAttributedString(string: text)
        self.append(normal)
        return self
    }
}

To code below is the usage, you can edit it how you'd like, but I have made it so you can easy just copy&paste it to your project:

            let formattedString = NSMutableAttributedString()
            formattedString
                .normal("You have managed to score ")
                .bold("\(CurrentScore)")
                .normal(". Current record is ")
                .bold("\(HighScore)")
                .normal(". Play again and give it another try!")

            gameOverDescriptionLabel.attributedText = formattedString

Upvotes: 1

TheAmateurProgrammer
TheAmateurProgrammer

Reputation: 9392

A solution without searching for the range would be to create 2 separate NSMutableAttributedString for current score and high score, and then append everything together.

let currentScoreString = NSMutableAttributedString(...)
let highscoreString = NSMutableAttributedString(...)

let finalString = NSMutableAttributedString(string: "You have managed to score ").append(currentScoreString)....

Upvotes: 0

matt
matt

Reputation: 535222

If the current score and high score are the same string, searching for the latter finds the former (because the search starts at the beginning).

There are lots of other, better ways to do this.

  • Perform the second search in a range starting after the result of the first search (range(of:) has a range: parameter, but you are not using it)

  • Instead of looking for the range of the high score, search for the surrounding boilerplate ("You have managed to score" and so on) and figure out where the numbers must be.

  • Use NSScanner or regular expressions to find the numerical expressions embedded in the string.

  • My favorite: mark each of the numbers with an "invisible" attribute and search for that attribute so that you can find the numbers reliably (example here).

Upvotes: 1

Related Questions