google1254 google1254 - 7 months ago 39
Swift Question

Why can't I bold just part of a string in Swift with NSMutableString?

The problem is that I can color half of the string but I cannot bold that half of the string.

Here's the code

var string = "blah blah blah blah blah"
var range = NSRange(location:0, length: 4)
//Apply to the label
value: UIFont.boldSystemFontOfSize([X size]), range: range)

range: range)
UILabel.text.attributedText = myMutableString

Any ideas why bolding bolds the entire string instead of just the first "blah"? Only the first "blah" is colored green.


I'm just posting an answer because it was fun to use the playgrounds interactively and see the UILabel changing in real time.

import UIKit

let label = UILabel(frame: CGRectMake(0, 0, 300, 100))
let text = "black green small"
var mutableString = NSMutableAttributedString(string: text)

let textCount = text.utf16.count // Thanks OOPer
    value: UIFont.boldSystemFontOfSize(20),
    range: NSRange(location:0, length: textCount*2/3)

    value: UIColor.greenColor(),
    range: NSRange(textCount/3..<textCount)

label.attributedText = mutableString

Image of interactive .playground file

To please OOPer, I learned a little bit more about character indexes

//: Playground - noun: a place where people can play

import UIKit

extension String { // tools
    func characterIndex(ofFraction fraction: Float) -> String.CharacterView.Index {
        let amountOfCharacters = Int(Float(self.characters.count) * fraction)
        return self.characters.startIndex.advancedBy(amountOfCharacters, limit: self.characters.endIndex)

    func utf16Index(characterIndex index: String.CharacterView.Index) -> String.UTF16View.Index {
        return String.UTF16View.Index(index, within: self.utf16)

    func utf16Offset(toIndex index: String.UTF16View.Index) -> String.UTF16View.Index.Distance {
        return self.utf16.startIndex.distanceTo(index)

extension String { // convenience
    func utf16Offset(ofFraction fraction: Float) -> String.UTF16View.Index.Distance {
        let correctIndexOfFraction = self.characterIndex(ofFraction: fraction)
        let translatedToUTF16 = self.utf16Index(characterIndex: correctIndexOfFraction)
        let absolutePosition = self.utf16Offset(toIndex: translatedToUTF16)
        return absolutePosition

func paintedString(text: String) -> NSAttributedString {
    let mutableString = NSMutableAttributedString(string: text)

    let firstTwoThirds = 0..<text.utf16Offset(ofFraction: 2/3)
    let lastTwoThirds = text.utf16Offset(ofFraction: 1/3)..<text.utf16.count

                               value: UIFont.boldSystemFontOfSize(30),
                               range: NSRange(firstTwoThirds)

                               value: UIColor.greenColor(),
                               range: NSRange(lastTwoThirds)

    return mutableString

func paintedLabel(text text: String) -> UILabel {
    let label = UILabel(frame: CGRectMake(0, 0, 300, 50))
    label.attributedText = paintedString(text)
    return label

paintedLabel(text: "black green small")
paintedLabel(text: "