Text Kit Tutorial: Getting Started

In this tutorial, you’ll learn how to use Text Kit in your iOS app to layout your text and create different visual styles. By Bill Morefield.

Leave a rating/review
Download materials
Save for later
Share
Update Note: Bill Morefield updated this tutorial for Swift 4.2, Xcode 10 beta 5, and iOS 12 beta 5. It was previously updated by Gabriel Hauber and originally written by Colin Eberhardt.

Early versions of iOS often used web views to render text with advanced styling such as bold, italics, and colors as they were easier to work with than the alternatives. The release of iOS 7 brought with it a new framework for working with text and text attributes: Text Kit. All text-based UIKit controls (apart from UIWebView) use Text Kit as shown in the following diagram:

TextRenderingArchitecture-iOS7

In this Text Kit tutorial, you’ll explore the various features of Text Kit as you create a simple note-taking app for the iPhone that features on-the-fly text styling, re-flowing text and dynamic-text resizing.

Getting Started

Use the Download Materials button at the top or bottom of this tutorial to download the materials for this tutorial. The starter project implements the user interface for the app so that you can stay focused on Text Kit.

Open the starter project in Xcode, and build and run the app. It will look like the following:

Textkit Start

The app creates an initial array of Note instances and renders them in a table view controller. Storyboards and segues detect cell selection in the table view and transition to the view controller where users can edit the selected note. Browse through the source code and play with the app a little to get a feel for how the app is structured and how it functions. When you’re done with that, move on to the next section, which discusses the use of dynamic type in your app.

Understanding Dynamic Type

iOS offers the option to enhance the legibility of text by increasing font weight and setting the preferred font size for apps. This feature is known as Dynamic Type and places the onus on your app to conform to user-selected font sizes and weights.

In iOS, open the Settings app and navigate to General ▸ Accessibility ▸ Larger Text to access Dynamic Type text sizes.

To make use of dynamic type, you app needs to specify fonts using styles rather than explicitly stating the font name and size. You use preferredFont(forTextStyle:) on UIFont to create a font for the given style using the user’s font preferences. You can see the six different font styles in this diagram:

TextStyles

The text on the left uses the smallest user selectable text size. The text in the center uses the largest, and the text on the right shows the effect of enabling the accessibility bold text feature.

Implementing Basic Support

Implementing basic support for dynamic text is straightforward. Instead of specifying exact fonts in your app, you request a font for a specific style. At runtime, iOS selects a suitable font based on the given style and the user’s text preferences.

Build and run the starter project app. Try changing the default text size in Preferences to various values. You’ll notice that the text size in list of notes changes. And you didn’t have to do a thing!

Open Main.storyboard to find out why. Locate the NotesListViewController and select the Title label in the prototype cell. You can see that the font is HeadLine. Since it’s a dynamic type, the system resizes it according to the user preferences.

If you click on a note and see the detail view, you’ll also notice that the notes do not reflect changes to the text size settings. You’ll fix that now.

Open NoteEditorViewController.swift and add the following to the end of viewDidLoad():

textView.font = .preferredFont(forTextStyle: .body)

Notice that you’re not specifying an exact font such as Helvetica Neue. Instead, you’re asking for an appropriate font for body text style using the .body constant.

Build and run the app again. The text view now honors the system text size. You can see the difference between the two in the screenshots below:

Note text styles

That looks pretty good, but there is one issue. Change the text size again under Settings ▸ General ▸ Accessibility ▸ Larger Text. Switch back to the app — without re-launching it — and you’ll notice that the note didn’t change the text size.

Responding to Updates

Like the table views, text views have built-in support for Dynamic Type; making it respond to the changes is as easy as setting a property.

Open NoteEditorViewController.swift and add the following code at the end of viewDidLoad():

textView.adjustsFontForContentSizeCategory = true

With that single line, you just told the text view to automatically reload the font when the system configuration changes. Isn’t it great when iOS does all the hard work for you?

Build and run your app. Change the text-size setting and verify that your app responds to the new user preferences.

Changing Layout

If you select a really small font size, your table view ends up looking a little sparse. When you select a really large font size, it ends up looking a bit crowded. These screenshots demonstrate the problem:

TableViewTextStyle

To ensure your table view looks good across the range of font sizes, your layout needs to be responsive to the user’s text settings. This is easy because Auto Layout and self-sizing cells do most of the work for you.

Add the following method to NotesListViewController:

override func viewDidLoad() {
  tableView.rowHeight = UITableView.automaticDimension
  tableView.estimatedRowHeight = 44.0
}

This code configures the table view to calculate the row height based on the cell content. You need to set an estimated height, which iOS will use as a default height before calculating the actual value.

Note: If you are not familiar with Self-sizing cells, you can learn more about them in our Self-sizing Table View Cells tutorial.

Build and run your app. Change the text size setting once more, and the table rows now change dynamically to fit the text size as shown in the screenshot below:

tableView autoresizing

Now, it’s time to give a new style to your app.

Implementing Letterpress Effect

The letterpress effect adds subtle shading and highlights that give text a sense of depth — much like the text has been slightly pressed into the screen. To get that effect, you’ll use NSAttributedString.

Open NotesListViewController.swift and replace tableView(_ tableView:, :cellForRowAtIndexPath:) with the following implementation:

override func tableView(_ tableView: UITableView, 
                        cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView
    .dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
  let note = notes[indexPath.row]
    
  let font = UIFont.preferredFont(forTextStyle: .headline)
  let textColor = UIColor(red: 0.175, green: 0.458, blue: 0.831, alpha: 1)
  let attributes: [NSAttributedString.Key: Any] = [
    .foregroundColor: textColor,
    .font: font,
    .textEffect: NSAttributedString.TextEffectStyle.letterpressStyle]
  let attributedString = NSAttributedString(string: note.title, attributes: attributes)
  cell.textLabel?.attributedText = attributedString
  return cell
}

This code creates an attributed string with a HeadLine style font, blue color and a letterpress text effect, and then assigns it to the text label in the cell.

Build and run your app. Now, the table view displays the text with a nice letterpress effect, as shown below:

Letterpress Text Style

Letterpress is a subtle effect, but that doesn’t mean you should overuse it. Visual effects may make your text more interesting, but they don’t always make your text more legible.