How to create custom view modifiers in SwiftUI

Jan 04, 2024#swiftui#modifiers

View modifiers are a way to customize and enhance the appearance and behavior of SwiftUI views. They can be applied to any view or another view modifier, producing a different version of the original value.

For example, you can use view modifiers to change the font, color, padding, alignment, animation, and more of a view.

Text("Hello, world!")
    .font(.title)
    .foregroundColor(.white)
    .padding()
    .background(Color.blue)
    .cornerRadius(10)

You can also create your own custom view modifiers by adopting the ViewModifier protocol and implementing the body(content:) method. The content parameter is the original view that the modifier is applied to, and the return value is the modified view.

To use this custom view modifier, you can either call the modifier(_:) method on any view and pass an instance of your custom view modifier, or you can create an extension on the View protocol and add a custom method that applies your modifier.

import SwiftUI

struct PinkBorder: ViewModifier {
    var radius: Double
    
    func body(content: Content) -> some View {
        content
            .clipShape(RoundedRectangle(cornerRadius: radius))
            .overlay {
                RoundedRectangle(cornerRadius: radius)
                    .stroke(.pink, lineWidth: 1.0)
            }
    }
}

extension View {
    func pinkBorder(radius: Double = 0) -> some View {
        modifier(PinkBorder(radius: radius))
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            Image("avatar")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .foregroundStyle(.tint)
                .frame(width: 100, height: 100)
                .pinkBorder(radius: 20)

        }
        .padding()
    }
}

You can also add parameters to your custom view modifier to make it more flexible and customizable. For example, you can add a color and a width parameter to your RedBorderAndShadow modifier and use them to set the border color and width:

struct RedBorderAndShadow: ViewModifier {
    let color: Color
    let width: CGFloat
    
    func body(content: Content) -> some View {
        content
            .border(color, width: width)
            .shadow(radius: 10)
    }
}

extension View {
    func redBorderAndShadow(color: Color = .red, width: CGFloat = 2) -> some View {
        modifier(RedBorderAndShadow(color: color, width: width))
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello, world!")
              .redBorderAndShadow(color: .green, width: 4)
        }
        .padding()
    }
}