Creating a custom view modifier in SwiftUI

Creating a custom view modifier in SwiftUI

Learn how to create custom view modifiers on SwiftUI.

Let’s understand how to create custom View Modifiers in a SwiftUI app project.

From the official Apple documentation, a modifier is what you apply to a view or another view modifier, producing a different version of the original value.

In SwiftUI, modifiers are one of the building blocks of how we create our user interfaces. They allow us to modify the Views we place on the UI visually, to add behaviors to our interface components, and to insert a view into another view structure.

Creating a view modifier

To create a view modifier you must create a structure that conforms to the ViewModifier protocol, which defines an associated type, a type alias, and a method that returns an object that conforms to the View protocol.

public protocol ViewModifier {

    /// The type of view representing the body.
    associatedtype Body : View

    /// Gets the current body of the caller.
    ///
    /// `content` is a proxy for the view that will have the modifier
    /// represented by `Self` applied to it.
    @ViewBuilder @MainActor func body(content: Self.Content) -> Self.Body

    /// The content view type passed to `body()`.
    typealias Content
}

API of the ViewModifier protocol as exposed by the SwiftUI framework.

To create a view modifier you must:

  • Define what the modifier is supposed to do
  • Create the modifier, conforming to the ViewModifier protocol
  • Create an extension to the View protocol to easily apply your modifier in your views

As a simple example, here is a modifier that applies a bold and rounded style to text views. It will simply apply the bold and font design modifiers to a view.

struct RoundedBoldFont: ViewModifier {
    func body(content: Content) -> some View {
        content
            .bold()
            .fontDesign(.rounded)
    }
}

Creating custom view modifiers with parameters

Sometimes we may want to pass parameters to our modifier like we usually do, for example, when adding padding to our views.

ContentView()
    .padding()
    .padding(50)
    .padding(.horizontal, 12)

This allows our modifiers to be more complex and customizable, or change the behavior of the modifier itself according to specific conditions. We may want in fact to change the style used on a view if it is selected or not or change the color used.

The following example creates a modifier to add a specific style to a view but the user can specify the accent color to be used.

struct FunViewModifier: ViewModifier {
    
    var color: Color
    
    func body(content: Content) -> some View {
        content
            .frame(maxWidth: .infinity)
            .aspectRatio(1, contentMode: .fit)
            .padding()
            .background {
                RoundedRectangle(cornerRadius: 25.0)
                    .foregroundStyle(.white)
            }
            .overlay {
                RoundedRectangle(cornerRadius: 25.0)
                    .stroke(lineWidth: 4)
                    .foregroundStyle(color)
            }
    }
}

Using a custom view modifier

To apply a modifier to a view you must use the modifier(_:) method.

Text("Create a View Modifier")
		.modifier(RoundedBoldFont())

To be able to use your custom view modifier as a method of an object that conforms to the View protocol, as you do with the SwiftUI framework modifiers, you just need to create an extension of the View protocol and create a method that applies your modifier.

extension View {
    func roundedBoldFont() -> some View {
        modifier(RoundedBoldFont())
    }
}