SwiftUI View Modifiers Tutorial for iOS

Learn how to refactor your code to create powerful custom SwiftUI view modifiers. Make your views look consistent and your code easier to read and maintain. By Danijela Vrzan.

4.7 (3) · 1 Review

Download materials
Save for later
Share

In SwiftUI, you can style your views using modifiers. You can use the built-in modifiers, but also create your own SwiftUI view modifiers. You’re probably already familiar with some of the built-in modifiers, like font() to set a Text view’s font attributes, frame() to constrain the size of a view and padding() to add whitespace around a view’s edges.

If you want to create your own SwiftUI view modifiers, there are two ways to do so. You can create a custom modifier by conforming to the ViewModifier protocol or you can extend View itself. The first approach has one advantage — you’re able to define custom stored properties.

In this tutorial, you’ll use an app called AdoptAPet, a simple master-detail view app, meaning there is a master view that shows high-level information, in this case an adoptable furry friend’s picture and name, and then a detail view that displays when the user taps a list row.

You’ll refactor AdoptAPet as you learn how to use SwiftUI’s ViewModifier protocol for:

  • Creating custom view modifiers.
  • Building new button styles.
  • Creating modifiers with conditional parameters.
  • Extending views to create reusable components.

Getting Started

Download the starter project by clicking Download Materials at the top or bottom of the tutorial.

Open AdoptAPet.xcodeproj inside the starter folder. Build and run to see the app in action:

AdoptAPet app running on iPhone 12 Pro Simulator showing the list of pets and detailed information about a selected pet

AdoptAPet is a simple app with a list of available animals and a detailed view displaying more information about the selected dog or cat.

Views in the app have a lot of styling modifiers, some of which repeat multiple times. This makes your code harder to read and maintain.

You’ll learn how to create custom SwiftUI view modifiers to make your views easier to read. But before that, take a moment to learn about SwiftUI view modifiers in general.

Swifty the bird thinking about different styling to wear and saying Hmmm... How will I modify today?

View Modifiers in SwiftUI

View modifiers are methods you call on your views to customize their appearance and behavior. Views and modifiers work together to define your UI.

You can use view modifiers to:

  • Add accessibility features.
  • Customize the design by applying styling such as colors, fonts and more.
  • Add actions and respond to events.
  • Configure other components, like toolbars and navigation bars.
  • Present other views, like sheets and alerts.

You can modify any type that conforms to View. This includes Text, Button, Image and any custom View you create.

The result of a SwiftUI view modifier is a View. This lets you chain multiple modifiers, listing them immediately one after another, to create another view.

SwiftUI comes with a set of predefined standard modifiers that you can use to design your UI. For example, when you want to add color to a Text view, you can apply the .foregroundColor() modifier.

You are also able to create your own custom modifiers using the ViewModifier protocol. The most common use case for creating custom view modifiers is bundling a set of modifiers you plan to reuse multiple places in your code.

Consider creating a button style and then using it across your app:

Three different tab views of an app showing one button style used across the app and same styling applied in multiple places in the code

You have to repeat your code in multiple places.

Creating your own modifier for a single component that you’ll reuse keeps your code DRY (Don’t Repeat Yourself):

Three different tab views of an app showing one button style used across the app using a view modifier for styling and having the styling code in a single place

It makes it easier to edit the code and gives you a single source of truth. It’s a small change that can make a big difference. Just imagine, the next time designers decide to switch from twenty-point padding down to 18, you won’t have to chase down this change multiple places in your code. It’ll be right there in one neat, easy-to-update place.

Read on to learn how to make this magic time-saving happen by building your own view modifiers.

Building a Title ViewModifier

You don’t think about optimizing your code while writing it. First, you make it work. Then, you do some refactoring.

When styling UI components, look for the lines of code where you repeat modifiers multiple times in different files.

In Xcode, open PetDetailedInformationView.swift and take a look at each of the top-level Text views inside the VStack:

Repeated set of modifiers in multiple places

Every title in the stack has identical styling and a repeated set of modifiers.

There are different approaches you could take here to avoid that repetition.

Every Text and HStack pair are identical. The only differences are each title’s text and the SFSymbol icon and detail property that follow it. You could extract the Text and HStack to a separate view and provide these values, but you still need to call it five times with different parameters.

Instead, you’ll create a view modifier.

Creating a Text ViewModifier

There’s a folder in your project called ViewModifiers and a file with the same name. You’ll create all your modifiers in this file to keep them handy in one place.

Keeping all custom modifiers in a single file makes them easier to maintain and change when needed. Think of it as creating an application-wide style guide. Anyone can refer to this view modifier file if they need to create a UI component that matches the defined app style or if they want to see how a particular look was achieved.

Open ViewModifiers.swift and replace // TODO: 1 with:

// 1
struct DetailedInfoTitleModifier: ViewModifier {
  // 2
  func body(content: Content) -> some View {
    content
      // 3
      .lineLimit(1)
      .font(.title2)
      .bold()
  }
}

Here’s what’s happening:

  1. You create a struct called DetailedInfoTitleModifier that conforms to the ViewModifier protocol. It’s a good idea to provide a descriptive name, especially when you start creating more modifiers.
  2. To conform to ViewModifier, you need to add the body(content:) method that returns some View. The content parameter is the view on which you apply the modifiers.
  3. Finally, you add all your modifiers.

Now, go back to PetDetailedInformationView.swift and replace the three modifiers below Text("Breed") with:

.modifier(DetailedInfoTitleModifier())

Build and run the app. Select a pet, and you’ll see nothing has changed:

Pet detailed information

That’s precisely the outcome you want, and everything looks exactly as intended. You haven’t changed the styling; you’ve only moved the modifiers to a different file.

Now, apply that same modifier to the rest of the titles by replacing existing modifiers below Text("Characteristics"), Text("Size"), Text("Sex") and Text("Age").

Notice how you need to call .modifier(DetailedInfoTitleModifier()) every time you want to apply your modifier. It looks redundant.

To avoid that, you’ll extend the Text to make your modifier accessible in a more convenient way.