I'm trying to find out what is practical difference between these two approaches. For example:
struct PrimaryLabel: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color.black)
.foregroundColor(Color.white)
.font(.largeTitle)
.cornerRadius(10)
}
}
extension View {
func makePrimaryLabel() -> some View {
self
.padding()
.background(Color.black)
.foregroundColor(Color.white)
.font(.largeTitle)
.cornerRadius(10)
}
}
Then we can use all of them following way:
Text(tech.title)
.modifier(PrimaryLabel())
Text(tech.title)
.makePrimaryLabel()
ModifiedContent(
content: Text(tech.title),
modifier: PrimaryLabel()
)
All of the approaches you mentioned are correct. The difference is how you use it and where you access it. Which one is better? is an opinion base question and you should take a look at clean code strategies and SOLID principles and etc to find what is the best practice for each case.
Since SwiftUI
is very modifier chain base, The second option is the closest to the original modifiers. Also you can take arguments like the originals:
extension Text {
enum Kind {
case primary
case secondary
}
func style(_ kind: Kind) -> some View {
switch kind {
case .primary:
return self
.padding()
.background(Color.black)
.foregroundColor(Color.white)
.font(.largeTitle)
.cornerRadius(10)
case .secondary:
return self
.padding()
.background(Color.blue)
.foregroundColor(Color.red)
.font(.largeTitle)
.cornerRadius(20)
}
}
}
struct ContentView: View {
@State var kind = Text.Kind.primary
var body: some View {
VStack {
Text("Primary")
.style(kind)
Button(action: {
self.kind = .secondary
}) {
Text("Change me to secondary")
}
}
}
}
We should wait and see what is the BEST practices in new technologies like this. Anything we find now is just a GOOD practice.
I usually prefer extensions, as they get you a more readable code and they are generally shorter to write. In fact I am currently working on an article with some tips. I finished an article about View extensions, available here.
However, there are differences. At least one. With ViewModifier you can have @State variables, but not with View extensions. Here's an example:
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, how are you?").modifier(ColorChangeOnTap())
}
}
}
struct ColorChangeOnTap: ViewModifier {
@State private var tapped: Bool = false
func body(content: Content) -> some View {
return content.foregroundColor(tapped ? .red : .blue).onTapGesture {
self.tapped.toggle()
}
}
}