Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating custom modifiers for Swift UI views

Tags:

ios

swift

swiftui

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.

like image 819
Luis Avatar asked Jul 08 '19 22:07

Luis


People also ask

What is SwiftUI view modifier?

A modifier that you apply to a view or another view modifier, producing a different version of the original value.

Can you extend SwiftUI view?

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.

What is var body some view in SwiftUI?

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”.

How do Views work in SwiftUI?

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.


1 Answers

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 vars 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:

Resulting view

like image 148
arsenius Avatar answered Sep 20 '22 19:09

arsenius