Search code examples
swiftswiftuiviewenumsshapes

View generating Shape based on enum


I want to give my view enum as parameter to generate corresponding Shape.

I tried something like this:

import SwiftUI

struct NotWorkingView: View {
    var body: some View {
        Card(shape: .capsule)
        Card(shape: .circle)
    }
}

struct Card: View {
    let shape: Shapes
    
    var body: some View {
        shape.val
    }
}

enum Shapes {
    case capsule
    case circle
    
    var val: any Shape {
        switch self {
        case .capsule:
            return Capsule()
        case .circle:
            return Circle()
        }
    }
}

but Xcode 'Failed to produce diagnostic'

I could do this:

import SwiftUI

struct WorkingView: View {
    var body: some View {
        Card(shape: Capsule())
        Card(shape: Circle())
    }
}

struct Card<Content: Shape>: View {
    let shape: Content
    
    var body: some View {
        shape
    }
}

but I wanted to be able to iterate over all valid shapes.

Is it possible to achieve that without making Card a template? Or maybe I need a wrapper for Card struct?


Solution

  • The reason for the error is the usage of any Shape. Use some View and use a Group or @ViewBuilder to return different types.

    enum Shapes {
        case capsule
        case circle
        
        var val: some View {
            Group{
                switch self {
                case .capsule:
                    Capsule()
                case .circle:
                    Circle()
                }
            }
        }
    }
    

    or:

    enum Shapes {
        case capsule
        case circle
    
        @ViewBuilder
        var val: some View {
                switch self {
                case .capsule:
                    Capsule()
                case .circle:
                    Circle()
                }
        }
    }
    

    Or even simpler:

    If the Card View doesn´t contain more than the Shape, conform your enum to View and rename the val var to body:

    struct NowWorkingView: View {
        var body: some View {
            Shapes.capsule
            Shapes.circle
        }
    }
    
    enum Shapes: View {
        case capsule
        case circle
        
        var body: some View {
            switch self {
            case .capsule:
                Capsule()
            case .circle:
                Circle()
            }
        }
    }