Imagine you have this kind of View below, a text in a box that looks like a card.

ZStack {
VStack {
Text("Hello World")
.font(.headline)
}
.frame(width: 200, height: 200, alignment: .center)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.white, lineWidth: 1)
)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white)
.shadow(color: Color.gray.opacity(0.5), radius: 3.0, x: 0.0, y: 0.0)
)
}If you find yourself in a situation where you have to copy this background and overlay modification multiple times in multiple places in your project, then it’s time to introduce ViewModifiers.
ViewModifier – A reusable modifier that you apply to a view or another view modifier, producing a different version of the original value.
Apple Documentation
Utilizing ViewModifier
Combining several modifiers to create a new modifier will help avoid having to write so much code in multiple places.
struct CardViewModifier: ViewModifier {
func body(content: Content) -> some View {
content
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.white, lineWidth: 1)
)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white)
.shadow(color: Color.gray.opacity(0.5), radius: 3.0, x: 0.0, y: 0.0)
)
}
}You can then apply modifier(_:) directly to a view:
ZStack {
VStack {
Text("Hello World")
.font(.headline)
}
.frame(width: 200, height: 200, alignment: .center)
.modifier(CardViewModifier()) // <---- Here
}A more common and better approach is to define an extension to View itself that incorporates the view modifier:
extension View {
func cardViewStyle() -> some View {
self.modifier(CardViewModifier())
}
}You can then apply the extension function to any view to achieve the same result:
ZStack {
VStack {
Text("Hello World")
.font(.headline)
}
.frame(width: 200, height: 200, alignment: .center)
.cardViewStyle() // <--- Here
}VieModifier with Parameters
You can also create a ViewModifier having parameters. What if you want to make the StrokeColor for the card customizable?
struct CardViewModifier: ViewModifier {
var strokeColor: Color // <--- Here
func body(content: Content) -> some View {
content
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(strokeColor, lineWidth: 1) // <--- Here
)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white)
.shadow(color: Color.gray.opacity(0.5), radius: 3.0, x: 0.0, y: 0.0)
)
}
}
extension View {
func cardViewStyle(strokeColor: Color = Color.white) -> some View {
self.modifier(CardViewModifier(strokeColor: strokeColor)) // <--- Here
}
}
struct SimpleView: View {
var body: some View {
ZStack {
VStack {
Text("Hello World")
.font(.headline)
}
.frame(width: 200, height: 200, alignment: .center)
.cardViewStyle(strokeColor: Color.red) // <--- Here
}
}
}
As you can see, using Modifiers can really save you some time as well as a number of lines of code. So you should consider adding that to your SwiftUI assets. ?
Cheers!