Exploring ViewModifiers
In SwiftUI, views are lightweight constructs that mainly consist of the
body
property and essential properties likealignment
for VStack, HStack, and ZStack, andaction
for Button. so how do we customize SwiftUI Views? Enter View Modifiers.
ViewModifiers
the ViewModifier
protocol allows you to create custom modifiers for views, enabling you to apply consistent styling and behavior across your app without repeating code. This is particularly useful for defining reusable components or styles that can be applied to various views.
Deep Dive into ViewModifier
ViewModifier
is a protocol. Other types can conform to, but no variable or value can just have the plain type ViewModifier
.
To make a type conform to ViewModifier
, we define a body
method that takes a Content
(whatever that is) and returns a Body
(whatever that is):
func body(content: Content) -> Body
A ViewModifier
is essentially just this one method, that takes a Content
as input and returns a Body
as output.
What’s Body
? ViewModifier
defines it as an associatedtype
with a constraint:
associatedtype Body : View
This means we get to pick the specific type known as Body
in our ViewModifier
, and we can pick any type for Body
as long as it conforms to the View
protocol.
let's look at an example
we create a simple custom modifier that adds a background color to any view by conforming to the ViewModifier. Note that we don’t have to name the type of View
returned by body
. We can use some View
and let Swift deduce the specific type.
struct ColorModifier:ViewModifier{
let color:Color
func body(content: Content) -> some View {
content
.background(color)
}
}
there are 3 ways to apply a custom Modifier.
1- modifier(_:)
All SwiftUI Views are backed by a modifier function which returns a ModifiedContent
instance. I will go over ModifiedContent in detail in another article.
so we can just add this modifier in any view and viola
2- Using ModifiedContent Directly
You can also use ModifiedContent
directly to create a view that applies a modifier. This approach is less common because it's more verbose, but it can be useful in certain scenarios where you need more control over the modifier application process:
ModifiedContent(content: Text("Hello, World!"), modifier: CustomModifier())
3- Custom Modifiers with Stored Properties
While SwiftUI has the .modifier API
to apply a value conforming to the ViewModifer protocol, SwiftUI’s built-in modifiers are all exposed as extensions on View and that is the practice we’ve applied here
Important gotcha
An important thing to understand is that when we apply a modifier to a View we are not directly modifying it. There are no properties to be modified. Instead, when a modifier is applied a ModifiedContent
is returned, which wrappers the View that we applied the modifier. so if there are multiple modifiers we keep wrapping the view with ModifiedContent.
Each time we apply a view modifier like padding or background to the text view, it gets wrapped in another layer. Looking at a chain of view modifiers like in the example above, we have to read from the bottom up to visualize the resulting view tree; the last view modifier, background in this example, becomes the topmost view in the view tree.
Apple provides a list of modifiers built in that you can use but you can also use a customized modifier according to your needs.
References: