Was wondering how it's possible to create modifiers for Swift UI views?
For example, let's say I have some view defined as so:
struct LabelView: View {
let font1: Font = .header
let font2: Font = .body
var body: Some View {
// two views, where one uses font1 and other uses font2
}
}
How would it be possible to create a modifier that allows something like:
LabelView()
.font1(.callout)
.font2(.body)
I'm trying to learn how to write API's in the declarative nature that Apple is pushing with Swift UI but it seems like documentation isn't complete on this. I've tried creating some sort of ViewModifier
type but I'm not really sure what I need to do with this, since it required I return _ModifiedContent<_, _>
and not exactly sure how to do this. Basically, is it possible to modify the properties of a view using a declarative syntax like the ones in the built in SwiftUI views.
A modifier that you apply to a view or another view modifier, producing a different version of the original value.
If you want to create your own SwiftUI view modifiers, there are two ways to do so. You can create a custom modifier by conforming to the ViewModifier protocol or you can extend View itself.
var body: some View { In swiftUI we can see that View is a protocol as the document says, “You create custom views by declaring types that conform to the `View` protocol. Implement the required `body` property to provide the content and behavior for your custom view”.
While UIKit uses an event-driven framework, SwiftUI is based on a data-driven framework. In SwiftUI, views are a function of state, not a sequence of events (WWDC 2019). A view is bound to some data (or state) as a source of truth, and automatically updates whenever the state changes.
As dfd linked to in the comments, you can create custom modifiers that use apple's provided modifiers. You can also create your own methods that modify var
s though.
Note: You can't use mutating methods here because function builders return immutable values. You'll get a compiler error. You need to make a copy of self
and return that.
extension LabelView {
func font1(_ font1: Font) -> Self {
var copy = self
copy.font1 = font1
return copy
}
}
You can also create a generic version that updates variables using a keypath:
extension View {
func modifying<T>(_ keyPath: WritableKeyPath<Self, T>, value: T) -> Self {
var copy = self
copy[keyPath: keyPath] = value
return copy
}
}
Usage of both versions:
struct LabelView: View {
var font1: Font = .headline
var font2: Font = .body
var body: some View { ... }
}
LabelView()
.modifying(\.font2, value: .callout)
.font1(.largeTitle)
And here is the result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With