Search code examples
swiftuiviewmodifier

What else i can use in modifier( :) function except of ViewModifier protocol in SwiftUI?


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.


Solution

  • In practice, the documentation you quoted is all you need to know, and you will pass ViewModifiers 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:

    1. Equatable
    2. View
    3. ViewModifier
    4. TableRowContent
    5. Scene
    6. MapContent
    7. DynamicViewContent
    8. DynamicTableRowContent
    9. 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 _TableRowContentModifiers (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 { ... }