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!