First, ViewModifier is a type of agreement.

Let’s start with the official example:

struct BorderedCaption: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.caption2)
            .padding(10)
            .overlay(
                RoundedRectangle(cornerRadius: 15)
                    .stroke(lineWidth: 1)
            )
            .foregroundColor(Color.blue)
    }
}
Copy the code

Here we write a structure BorderedCaption following the ViewModifier agreement. The method body returns a view that has some format we prefer. The ViewModifier is essentially the function, which only has the body method, receives the Content, and then returns a View.

But what is this Content?

If we skip to Definition, we can see:

Available (iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public protocol ViewModifier { /// The type of view representing the body. associatedtype Body : View /// Gets the current body of the caller. /// /// `content` is a proxy for the view that will have the modifier /// represented by `Self` applied to it. func body(content: Self.Content) -> Self.Body /// The content view type passed to `body()`. typealias Content }Copy the code

It is a TypeAlias. But there’s still no answer for us. What is it?

Xcode is programmed to not display common symbols in the SDK if the symbol begins with an underscore (_). However, by looking up SwiftUI in the.swiftInterface file, we can see the true definition of ViewModifier, including hidden symbols.

Available (iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) public protocol ViewModifier { static func _makeView(modifier: SwiftUI._GraphValue<Self>, inputs: SwiftUI._ViewInputs, body: @escaping (SwiftUI._Graph, SwiftUI._ViewInputs) -> SwiftUI._ViewOutputs) -> SwiftUI._ViewOutputs static func _makeViewList(modifier: SwiftUI._GraphValue<Self>, inputs: SwiftUI._ViewListInputs, body: @escaping (SwiftUI._Graph, SwiftUI._ViewListInputs) -> SwiftUI._ViewListOutputs) -> SwiftUI._ViewListOutputs associatedtype Body : SwiftUI.View func body(content: Self.Content) -> Self.Body typealias Content = SwiftUI._ViewModifier_Content<Self> }Copy the code

We can see that Content is an alias for _ViewModifier_Content. This structure does not define any interesting public interface, but (in the extension) complies with View. So this tells us that when we write our ViewModifier, our Body method will receive some View (the specific type is defined by the framework and we can call it Content) and return some View (we can choose a specific return type).

And then, we usually write an extension to View.

extension View {
    func borderedCaption() -> some View {
        modifier(BorderedCaption())
    }
}
Copy the code

Here we write a method borderedCaption that returns a value modifier to receive an instantiated object borderedCaption () that follows the ViewModifier

Then we can use:

Image(systemName: "bus")
    .resizable()
    .frame(width:50, height:50)
Text("Downtown Bus")
    .borderedCaption()
Copy the code

As we can see, Text can directly call our own wrapped ViewModifer to change the style.

Of course, if you don’t want to extend the View, you can also use this:

Image(systemName: "bus")
    .resizable()
    .frame(width:50, height:50)
Text("Downtown Bus")
    .modifier(BorderedCaption())
Copy the code