Search code examples
swiftswiftuicomposition

Is it possible to write a function to compose an arbitrary number of SwiftUI `ViewModifier's?


Consider the following ViewModifier that applies padding to a particular View

enum Padding {
    case small
    case medium
    case large
}

private struct PaddingModifier: ViewModifier {
    var edgeSet: Edge.Set = .all
    var size: Padding

    func body(content: Content) -> some View {
        return content.padding(edgeSet, getSize())
    }

    func getSize() -> CGFloat {
        switch size {
        case .small:
            return 2
        case .medium:
            return 8
        case .large:
            return 16
        }
    }
}

To make the ViewModifier more readable, typically I'd add an extension function to View

extension View {
    func padding(_ size: Padding, _ set: Edge.Set = .all) -> some View {
        return modifier(PaddingModifier(edgeSet: set, size: size))
    }
}

However, let's say I want to apply this modifier to an arbitrary list of Edge.Set values. How can I write a function with the signature (Padding, [Edge.Set]) -> some View that applies PaddingModifier for each Edge.Set?

My first thought was something like below, but Self cannot conform to some View

extension View {
    func padding(_ size: Padding, _ set: Edge.Set = .all) -> some View {
        return modifier(PaddingModifier(edgeSet: set, size: size))
    }

    func padding(_ size: Padding, _ set: [Edge.Set]) -> some View {
        set.reduce(self) { $0.padding(size, $1) }
    }
}

Solution

  • The Edge.Set is a OptionSet, so with first modifier it is already possible to code (similarly to built-in .padding([.leading, .trailing], 20))

    Text("Demo")
       .padding(.small, [.leading, .trailing])
    

    it looks like padding(_ size: Padding, _ set: [Edge.Set]) overthinked.