View generating Shape based on enum

62 Views Asked by At

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?

1

There are 1 best solutions below

0
burnsi On BEST ANSWER

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()
        }
    }
}