I am new in SwiftUI, and now I am investigating ViewModifiers. All tutorials are very simple, just create new Struct, and body function + extension. But what does Apple say about it:
From developer.apple.com :
nonisolated
func modifier<T>(_ modifier: T) -> ModifiedContent<Self, T>
and about ModifiedContent<Self, T>
If content is a View and modifier is a ViewModifier, the result is a View. If content and modifier are both view modifiers, then the result is a new ViewModifier combining them.
so no mention that T must conform ViewModifier protocol. What else i can use then? Do someone have good tutorial or explanation?
I also try to read comments in Xcode but this same like on site.
In practice, the documentation you quoted is all you need to know, and you will pass ViewModifier
s into the modifier
method 100% of the time. The reason why T
is not constrained is because it doesn't need to be.
If you pass in something that is not a ViewModifier
, the ModifiedContent
produced will not conform to View
, and so you can't use it as a View
anyway.
As the documentation says, ModifiedContent<Content, Modifier>
only conforms to View
when Content
conforms to View
and Modifier
conforms to ViewModifier
.
A more interesting question is, why are the Content
and Modifier
type parameters of ModifiedContent
unconstrained? What else can ModifiedContent
be used for? The answer is mostly implementation details, so only read on if you are interested.
Go to the documentation page of ModifiedContent
, and scroll down to the "Conforms To" section. This is where you can discover what other things a ModifiedContent
can be used as.
At the time of writing, ModifiedContent
conforms to the following protocols:
Equatable
View
ViewModifier
TableRowContent
Scene
MapContent
DynamicViewContent
DynamicTableRowContent
DynamicMapContent
Equatable
is not very interesting, and you are already aware of 2 and 3.
4 requires the Modifier
type parameter to conform to _TableRowContentModifier
. Some of the modifier methods for TableRowContent
produce a ModifiedContent<Self, XXX>
. For example, itemProvider
probably applies the ItemProviderTableRowModifier
. You cannot directly apply a ItemProviderTableRowModifier
because it has no public initialisers. It is also not possible to write your own _TableRowContentModifier
s (not in a meaningful way, at least).
5 and 6 are similar. You can't directly create ModifiedContent
that acts like a MapContent
or Scene
. You can only create these by applying the modifier methods in Scene
or MapContent
.
7, 8, and 9 are protocols that inherit from 2, 4 and 6 respectively. These are basically specialised protocols for when you use ForEach
. For example, when you use ForEach
in a view body, the view created will conform to DynamicViewContent
, and you get access to additional methods like onMove
, onDelete
etc. The same thing can be said for when you use ForEach
in a Map
and Table
.
ModifiedContent
conforming to these DynamicXXX
protocols when the Content
type conforms to these protocols, so that you still have access to onDelete
, onMove
, etc, even after you added modifiers.
ForEach(things) { thing in ... }
.modifier(SomeModifier())
// I can still call 'onDelete' here, because 'modifier' returns something that conforms to 'DynamicViewContent'
.onDelete { ... }