Skip to content

Instantly share code, notes, and snippets.

@maximkrouk
Created March 30, 2020 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maximkrouk/1eac0ad7b8e0c5e23b2f9f6285403631 to your computer and use it in GitHub Desktop.
Save maximkrouk/1eac0ad7b8e0c5e23b2f9f6285403631 to your computer and use it in GitHub Desktop.
Functional view modifier
import SwiftUI
struct _ViewModifier<Input: View, Output: View>: ViewModifier {
typealias Body = Output
typealias Content = _ViewModifier_Content<_ViewModifier<Input, Output>>
var modification: (Content) -> Output
func body(content: Content) -> Output {
modification(content)
}
}
extension View {
func modifier<T: View>(_ viewModifier: _ViewModifier<Self, T>)
-> ModifiedContent<Self, _ViewModifier<Self, T>> {
_modifier(viewModifier)
}
private func _modifier<T: ViewModifier>(_ viewModifier: T)
-> ModifiedContent<Self, T> {
modifier(viewModifier)
}
}
@maximkrouk
Copy link
Author

maximkrouk commented Mar 30, 2020

Usage

I use it with this extension:

extension View {
    func eraseToAnyView() -> AnyView { .init(self) }
}

And modifier declaration now looks like this:

extension _ViewModifier {

    // Declaration
    static func largeButton<T: View>() -> _ViewModifier<T, AnyView> {
        let size = CGSize(width: 300, height: 50)
        let fontModifier: CGFloat = 0.4
        return .init { content in
            content
                .font(.system(size: round(size.height * fontModifier), weight: .medium))
                .frame(
                    idealWidth: size.width,
                    maxWidth: .infinity,
                    idealHeight: size.height,
                    maxHeight: size.height
                )
                .eraseToAnyView()
        }
    }
    
}

// Usage
Button(action: someAction}) { Text("TapMe") }
    .modifier(.largeButton())

instead of this

// Declaration
struct LargeButtonModifier: ViewModifier {
    let size = CGSize(width: 300, height: 50)
    let fontModifier: CGFloat = 0.4
    func body(content: Content) -> some View {
        content
        .font(.system(size: round(size.height * fontModifier), weight: .medium))
        .frame(idealWidth: size.width, maxWidth: .infinity,
               idealHeight: size.height, maxHeight: size.height)
    }
}

// Usage
Button(action: someAction}) { Text("TapMe") }
    .modifier(LargeButtonModifier())

Back to index

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment