How to create custom view modifiers in SwiftUI?

Image for post
Image for post

We know that every element in SwiftUI is a View. A modifier is used to change the behaviour of the View. Let’s see this with an example,

Button(action: {
print("Submit clicked")
}){
Text("Submit")
.foregroundColor(.white)
.padding(.horizontal, 30)
.padding(.vertical)
.background(Color.red)
.clipShape(Capsule())
.shadow(color: .red, radius: 10, x: 0, y: 5)
}

We have created a button view and it looks like below,

Image for post
Image for post

Here we have applied .foreground(), .background(), clipseShape(), shadow(), padding() modifiers to the Text view.

Consider you want to use the same theme for the entire app and you will have many button views in multiple screens of the app. We cannot repeatedly apply the same modifiers for many times. It will lead us to Code duplication.

To avoid this scenario we can use Custom View Modifiers. Let’s learn how to create our own view modifier.

Creating custom view modifiers consists of the following steps

  1. Create a struct with ViewModifier protocol.
  2. Add custom modifier method in View extension
  3. Use custom view modifier

Step 1:

Create a struct with ViewModifier protocol.

struct ButtonModifier: ViewModifier {
func body(content: Content) -> some View {
content
.foregroundColor(.white)
.padding(.horizontal, 30)
.padding(.vertical)
.background(Color.red)
.clipShape(Capsule())
.shadow(color: .red, radius: 10, x: 0, y: 5)
}
}

Here, we have created ButtonModifier struct with ViewModifier protocol. Inside this struct, we have a body method which has content as an argument and some View as return type.

This content is the view where we are going to apply the modifiers.

Step 2:

extension View {
func buttonModifier() -> some View {
self.modifier(ButtonModifier())
}
}

Now, we have created an extension for View and added a function - buttonModifier(). This is going to be our custom modifier.

Inside the method, we are attaching our step 1 ViewModifier struct to the View using self.modifier() method.

Step 3:

Now we can use this custom modifier in our ContentView like below,

Button(action: {
print("Submit clicked")
}){
Text("Submit")
.buttonModifier()
}

We can see that the same design has been applied to the button with our custom modifiers.

How to pass values to the custom modifiers?

What if we want to pass a value to the custom modifier? Let’s change the modifier. This time we will pass a colour value in it.

struct ButtonModifier: ViewModifier {
var bgColor: Color
func body(content: Content) -> some View {
content
.foregroundColor(.white)
.padding(.horizontal, 30)
.padding(.vertical)
.background(bgColor)
.clipShape(Capsule())
.shadow(color: .red, radius: 10, x: 0, y: 5)
}
}

In the above snippet, we have introduced a Color variable and passing that value in the .background modifier.

We need to modify the same in the View extension.

extension View {
func buttonModifier(bgColor: Color) -> some View {
self.modifier(ButtonModifier(bgColor: bgColor))
}
}

and Button in which we used the custom modifier.

Button(action: {
print("Submit clicked")
}){
Text("Submit")
.buttonModifier(bgColor: .blue)
}

User can pass any colour in the bgColor argument. This is just an example we can create any number of arguments and any kind of arguments to a custom modifier.

Conclusion:

Custom view modifiers are playing a huge role when we build a large application. This will reduce code repetition.

Hope you enjoyed it. Thank you 🙏

Written by

Automation QA Engineer by profession. Learning iOS Development.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store