iosswiftswiftuiswiftui-listswift-protocols

How can I make a closure to conform to 'AccessibilityRotorContent'?


I created a view which displays a stack of cards. I am passing two parameters to it:

struct CardStack: View {
    var cards: [Card]
    var content: (Int, Card) -> CardView

    init(cards: [Card], @ViewBuilder content: @escaping (Int, Card) -> CardView) {
        self.cards = cards
        self.content = content
    }
    
    var body: some View {
        ZStack {
            ForEach(Array(cards.enumerated()), id: \.element.id) { index, card in
                content(index, card)
            }
        }
    }
}

It works fine when the closure contains just the CardView, but as soon as I add any view modifier to the CardView (and I need to add many of them), the returned type of the closure changes to some View, and I get an error: Cannot convert return expression of type 'some View' to return type 'CardView'

var deckBody: some View {
    CardStack(cards: viewModel.cards) { index, card in  // Error: Cannot convert return expression of type 'some View' to return type 'CardView'
        CardView(card: card)
            .zIndex(Double(index))
    }
}

Then, when I amend CardView to expect a closure returning any View instead of the CardView, I get another error Static method 'buildExpression' requires that 'Content' conform to 'AccessibilityRotorContent':

struct CardStack: View {
    var cards: [Card]
    var content: (Int, Card) -> any View

    init(cards: [Card], @ViewBuilder content: @escaping (Int, Card) -> any View) {
        self.cards = cards
        self.content = content
    }
    
    var body: some View {
        ZStack {
            ForEach(Array(cards.enumerated()), id: \.element.id) { index, card in
                content(index, card)     // Error: Static method 'buildExpression' requires that 'Content' conform to 'AccessibilityRotorContent'
            }
        }
    }
}

Why should I, and how can I make the closure conform to 'AccessibilityRotorContent'?


Solution

  • CardStack should have a generic type parameter indicating the type of View that each card is displayed as.

    struct CardStack<CardContent: View>: View {
        var cards: [Card]
        var content: (Int, Card) -> CardContent
    
        init(cards: [Card], @ViewBuilder content: @escaping (Int, Card) -> CardContent) {
            self.cards = cards
            self.content = content
        }
    
        ...
    }