NSMutableAttributedString Tutorial by Example

Upgrade to Swift 5

String class is very rich and great in Swift, but as there is a lot of requirements to have formatted string. Using NSMutableAttributedString and NSAttributedString we can achieve multiple fonts, color, underline, strikethrough, shadow and a lot more. Let’s explore these class…
Let’s create new a project and add a swift file.

-Import UIKit
-Create extension of  NSMutableAttributedString

import Foundation
import UIKit
extension NSMutableAttributedString {
}

NSMutableAttributedString requires two properties one is attribute(Dictionary) and second one is NSRange. All keys of attributes are define in NSAttributedString.Key extension class and few keys are below:


NSAttributedString.Key.foregroundColor // to change color of string
NSAttributedString.Key.font // to change font of string
NSAttributedString.Key.backgroundColor // to change background color of string
NSAttributedString.Key.underlineStyle // underline below text
NSAttributedString.Key.shadow // add shadow over string
NSAttributedString.Key.paragraphStyle // for paragraph style

NSRange tell us the position of substring and we apply the attribute that position. First we need to change our String to NSMutableAttributedString for this use below function.

Add below code in NSMutableAttributedString Extension.

extension NSMutableAttributedString {
    
    class func getAttributedString(fromString string: String) -> NSMutableAttributedString {
        return NSMutableAttributedString(string: string)
    }
}

Now Let’s add more two functions in the NSMutableAttributedString Extension to apply attributes on range and substring


extension NSMutableAttributedString {
    
    class func getAttributedString(fromString string: String) -> NSMutableAttributedString {
        return NSMutableAttributedString(string: string)
    }
    
    func apply(attribute: [NSAttributedString.Key: Any], subString: String)  {
        if let range = self.string.range(of: subString) {
            self.apply(attribute: attribute, onRange: NSRange(range, in: self.string))
        }
    }
    
    func apply(attribute: [NSAttributedString.Key: Any], onRange range: NSRange) {
        if range.location != NSNotFound {
            self.setAttributes(attribute, range: range)
        }
    }
}

Color Attribute

Let’s create a function to apply different different color on a substring or given range. Add these two functions in your extension class.


  // Apply color on substring
  func apply(color: UIColor, subString: String) {
    
    if let range = self.string.range(of: subString) {
      self.apply(color: color, onRange: NSRange(range, in:self.string))
    }
  }
  
  // Apply color on given range
  func apply(color: UIColor, onRange: NSRange) {
    self.addAttributes([NSAttributedString.Key.foregroundColor: color],
                       range: onRange)
  }

Now move to your ViewController and in viewDidLoad function create a string and convert this string to NSMutableAttributedString.


let text = "This is a colorful attributed string"
let attributedText = NSMutableAttributedString.getAttributedString(fromString: text)

Now we have a attributed string and we are going to apply different color on each word, let’s see how it’s work. Add below code in your viewDidLoad function.


attributedText.apply(color: appRedColor, subString: "This")
attributedText.apply(color: appYellowColor, onRange: NSMakeRange(5, 4)) //Range of substring "is a"
attributedText.apply(color: .purple, subString: "colorful")
attributedText.apply(color: appBlueColor, subString: "attributed")
attributedText.apply(color: darkOrangeColor, subString: "string")

Now drag and drop a UILabel in interface and create outlet of this UILabel. Assign this attributed string to this label. The complete function will be.


override func viewDidLoad() {
	super.viewDidLoad()
	let text = "This is a colorful attributed string"
	let attributedText = NSMutableAttributedString.getAttributedString(fromString: text)
	attributedText.apply(color: .red, subString: "This")
	attributedText.apply(color: .darkGray, onRange: NSMakeRange(5, 4)) //Range of substring "is a"
	attributedText.apply(color: .purple, subString: "colorful")
	attributedText.apply(color: .blue, subString: "attributed")
	attributedText.apply(color: .orange, subString: "string")
	self.firstLabel.attributedText = attributedText
    }

Now below will be the output.

Font Attribute

Using NSAttributedString.Key.font key we can have different different font in a single string. Let’s see how it works. Add below tow function in your Attributed.swift file.


  // Apply font on substring
  //1
  func apply(font: UIFont, subString: String)  {
    
    if let range = self.string.range(of: subString) {
      self.apply(font: font, onRange: NSRange(range, in: self.string))
    }
  }
  
  // Apply font on given range
  //2
  func apply(font: UIFont, onRange: NSRange) {
    self.addAttributes([NSAttributedString.Key.font: font], range: onRange)
  }   

1. In this function pass the UIFont object and substring in which you want to apply the font.
2. Sometime there may be a case that a string have two substrings, so in this case use the second function and pass UIFont and NSRange object.
In your ViewController class create a second UILabel and add below code in your viewDidLoad function.


let text = "This string is having multiple font"
let attributedText = NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.apply(font: UIFont.boldSystemFont(ofSize: 24), subString: "This")
attributedText.apply(font: UIFont.boldSystemFont(ofSize: 24), onRange: NSMakeRange(5, 6))
attributedText.apply(font: UIFont.italicSystemFont(ofSize: 20), subString: "string")
attributedText.apply(font: UIFont(name: "HelveticaNeue-BoldItalic", size: 20)!, subString: " is")
attributedText.apply(font: UIFont(name: "HelveticaNeue-ThinItalic", size: 20)!, subString: "having")
attributedText.apply(color: UIColor.blue, subString: "having")
attributedText.apply(font: UIFont(name: "HelveticaNeue-CondensedBlack", size: 20)!, subString: "multiple")
attributedText.apply(color: appRedColor, subString: "multiple")
self.secondLabel.attributedText = attributedText

Output will be the below:

Underline Attribute

We can achieve the underline beneath any substring using NSAttributedString.Key.underlineStyle key. Add below functions in the AttributedString.swift file.


  // Underline string
  func underLine(subString: String) {
    if let range = self.string.range(of: subString) {
      self.underLine(onRange: NSRange(range, in: self.string))
    }
  }
  
  // Underline string on given range
  func underLine(onRange: NSRange) {
    self.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue],
                       range: onRange)
  }
Create a another UILabel in your ViewController class and add below code in your viewDidLoad function.


let text = "This is underline string"
let attributedText = NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.underLine(subString: "This is underline string")
self.thirdLabel.attributedText = attributedText

Below will be the output of underline text.

Strikethrough and Stroke Attribute

Strikethrough and stroke attributes are really awesome and pretty easy to use. Add below functions in the AttributedString.swift file.


  // Apply Strikethrough on substring
  //1
  func strikeThrough(thickness: Int, subString: String)  {
    if let range = self.string.range(of: subString) {
      self.strikeThrough(thickness: thickness, onRange: NSRange(range, in: self.string))
    }
  }
  
  // Apply Strikethrough on given range
  //2
  func strikeThrough(thickness: Int, onRange: NSRange)  {
    
    self.addAttributes([NSAttributedString.Key.strikethroughStyle : NSUnderlineStyle.thick.rawValue],
                       range: onRange)
  }

  // Apply stroke on substring
  //3
  func applyStroke(color: UIColor, thickness: Int, subString: String) {
    if let range = self.string.range(of: subString) {
      self.applyStroke(color: color, thickness: thickness, onRange: NSRange(range, in: self.string))
    }
  }
  
  // Apply stroke on give range
  //4
  func applyStroke(color: UIColor, thickness: Int, onRange: NSRange) {
    self.addAttributes([NSAttributedString.Key.strokeColor : color],
                       range: onRange)
    self.addAttributes([NSAttributedString.Key.strokeWidth : thickness],
                       range: onRange)
  }

In 1 and 2: pass thickness of strike to apply on given range or substring.
3 and 4: these two functions will be use to create stroke string, which required three parameters, color of stroke, thickness of stroke and substring or range. Now create one more UILabel in your ViewController and add below code in your viewDidLoad function


let text = "This is a strike and underline stroke string"
let attributedText = NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.strikeThrough(thickness: 2, subString: "This is a")
attributedText.underLine(subString: "underline")
attributedText.applyStroke(color: appRedColor, thickness: 2, subString: "stroke string")
self.fourthLabel.attributedText = attributedText

Now the output will be like below

Shadow Attribute

These days shadow string is getting pretty popular. It’s give a string a 3D look and make it more beautiful. To add shadow over any string you need to set these properties, shadow color, widht, height and radius. Now add below two functions in your AttributedString.swift file.


  // Apply shadow color on substring
  //1
  func applyShadow(shadowColor: UIColor, shadowWidth: CGFloat,
                   shadowHeigt: CGFloat, shadowRadius: CGFloat,
                   subString: String) {
    if let range = self.string.range(of: subString) {
      self.applyShadow(shadowColor: shadowColor, shadowWidth: shadowWidth,
                       shadowHeigt: shadowHeigt, shadowRadius: shadowRadius,
                       onRange: NSRange(range, in: self.string))
      
    }
  }
  
  // Apply shadow color on given range
  //2
  func applyShadow(shadowColor: UIColor, shadowWidth: CGFloat,
                   shadowHeigt: CGFloat, shadowRadius: CGFloat,
                   onRange: NSRange) {
    let shadow = NSShadow()
    shadow.shadowOffset = CGSize(width: shadowWidth, height: shadowHeigt)
    shadow.shadowColor = shadowColor
    shadow.shadowBlurRadius = shadowRadius
    self.addAttributes([NSAttributedString.Key.shadow : shadow], range: onRange)
  }

Now create one more UILabel in your class and add below code in your viewDidLoad


let text = "This string is having a shadow"
let attributedText = NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.applyShadow(shadowColor: .black, shadowWidth: 4.0, shadowHeigt: 4.0, shadowRadius: 4.0, subString: "This string is")
attributedText.applyShadow(shadowColor: .black, shadowWidth: 0, shadowHeigt: 0, shadowRadius: 5.0, subString: "having")
attributedText.applyShadow(shadowColor: .black, shadowWidth: 4.0, shadowHeigt: 4.0, shadowRadius: 4.0, subString: "a shadow")
self.fifthLabel.attributedText = attributedText

Now the output will be like below.

If we put all UILabel together screen will be look like below.

You can download the full source code from here.


Read our next article: Everything about CAGradientLayer in just 5 mins

3 comments on “NSMutableAttributedString Tutorial by Example

  1. Jimmy

    Way cool! Some extremely valid points! I appreciate you penning this post and also the rest of the website is
    extremely good. It’s appropriate time to make a few plans for the longer term and
    it’s time to be happy. I have read this put up and if I may just I desire to counsel you some attention-grabbing issues or suggestions.
    Perhaps you can write subsequent articles regarding
    this article. I want to read more things approximately
    it! I have been browsing on-line more than 3 hours today, yet I by no means found
    any attention-grabbing article like yours. It is pretty
    worth sufficient for me. In my view, if all site owners and
    bloggers made good content material as you did, the internet will probably be a lot more helpful than ever before.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *