Close modal

Blog Post

Using NSAttributedString for advanced formatting

Development
Sun 17 December 2017
0 Comments


What are attributed strings?

iOS (and OSX) has excellent support for attributed strings, they allow you to have rich formatting inside standard controls such as UILabel or UITextView. You can set various attributes over all or part of the string, and different string ranges may have differing attributes, which becomes very useful. Here are the non-deprecated attributes supported in iOS 11.1:

  • accessibilityAlignment
  • accessibilityAnnotationTextAttribute
  • accessibilityAttachment
  • accessibilityAutocorrected
  • accessibilityBackgroundColor
  • accessibilityCustomText
  • accessibilityFont
  • accessibilityForegroundColor
  • accessibilityLanguage
  • accessibilityLink
  • accessibilityListItemIndex
  • accessibilityListItemLevel
  • accessibilityListItemPrefix
  • accessibilityMarkedMisspelled
  • accessibilityMisspelled
  • accessibilityShadow
  • accessibilityStrikethrough
  • accessibilityStrikethroughColor
  • accessibilitySuperscript
  • accessibilityUnderline
  • accessibilityUnderlineColor
  • attachment
  • backgroundColor
  • baselineOffset
  • cursor
  • expansion
  • font
  • foregroundColor
  • glyphInfo
  • kern
  • ligature
  • link
  • markedClauseSegment
  • obliqueness
  • paragraphStyle
  • shadow
  • spellingState
  • strikethroughColor
  • strikethroughStyle
  • strokeColor
  • strokeWidth
  • superscript
  • textAlternatives
  • textEffect
  • toolTip
  • underlineColor
  • underlineStyle
  • verticalGlyphForm
  • writingDirection

As you can see, that's alot of flexibility, and you can assign multiple attributes to differemt parts of a string, allowing the type of formatting many people would goto a webview to use, however attributed strings are much more efficient and faster than a webview.

How To Use

You create an instance of NSMutableAttributedString or NSAttributedString, providing possible attributes that are applicable to the whole range of the string in a dictionary. If the object is a mutable instance you can also call setAttributes method, and provide the new attributes and the applicable range as an NSRange object. In swift3 the key names for the dictionary fall under the NSAttributedStringKey class, with possible values as listed above. To use the string in a UIKit object, you assign the attributedText property rather than the text property.

let fancyText = NSMutableAttributedString(string: "Heading\nBody", attributes: [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 13.0)])
fancyText.setAttributes([NSAttributedStringKey.font : UIFont.systemFont(ofSize: 16.0)], range: NSMakeRange(0, 4))
let label = UILabel()
label.attributedText = fancyText

Example Playground

import UIKit

let demoFrame = CGRect(x: 0, y: 0, width: 320, height: 100)
let title = "Helpful Tip:"
let subtitle = "Attributed strings and views are awesome. Here is more text to ensure it wraps lines."


let normalAttributes : [NSAttributedStringKey : Any] = [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 13.0), NSAttributedStringKey.foregroundColor : UIColor.white]
let headingAttributes : [NSAttributedStringKey : Any] = [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 16.0), NSAttributedStringKey.foregroundColor : UIColor.lightGray]

let attributedParagraph = NSMutableAttributedString(string: title + "\n" + subtitle, attributes: normalAttributes)

attributedParagraph.setAttributes(headingAttributes, range: NSMakeRange(0, title.characters.count))

let textview = UITextView(frame: demoFrame)
textview.isEditable = false
textview.showsVerticalScrollIndicator = false
textview.backgroundColor = UIColor.clear
textview.attributedText = attributedParagraph

let label = UILabel(frame: demoFrame)
label.numberOfLines = 0
label.attributedText = attributedParagraph

label

label.sizeToFit()

textview

How it looks

Playground Output

Conclusion

Attributed strings are sometimes overlooked, but provide a way to present text richly without using UIWebview or CoreText. Consider using them for paragraph based layout or even bullet point rendering.

Using the below constructor for NSAttributedString, you can even convert HTML markup into attributed strings.

NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)