1

I am trying to display multiple previews of the card view (Apple's SwiftUI tutorial). I managed to do it manually using the Group struct.

struct CardView_Previews: PreviewProvider {
    
    static var previews: some View {
        Group {
            CardView(scrum: DailyScrum.data[0])
                .background(DailyScrum.data[0].color)
            CardView(scrum: DailyScrum.data[1])
                .background(DailyScrum.data[1].color)
        }.previewLayout(.fixed(width: 400, height: 60))
    }
}

I would like to automate the display of four cells based on test data with a ForEach, but the following fails to build and the compiler fails to produce a diagnostic for the expression.

struct CardView_Previews: PreviewProvider {
    
    static var previews: some View {
        Group {
            ForEach(DailyScrum.data) { scrum in
                CardView(scrum: scrum)
                    .background(scrum.color)
            }
        }.previewLayout(.fixed(width: 400, height: 60))   
    }   
}

Is there a way to construct the previews without explicitly creating each preview ?

Gael
  • 459
  • 3
  • 18

2 Answers2

1

You can't think of a PreviewProvider as part of your running app. It ONLY is used when you are using a preview on a canvas for that particular view. Therefore, any data you need to provide to the view, must be provided from, or through, the PreviewProvider itself.

From your code, it appears that your model, DailyScrum contains an array data that you use to fill the cells. Therefore, if you want to declare it in the PreviewProvider you would declare it something like this:

struct CardView_Previews: PreviewProvider {
    
    let dailyScrum = DailyScrum(
        // Initialize your data here
    )

    static var previews: some View {
        Group {
            ForEach(dailyScrum.data) { scrum in
                CardView(scrum: scrum)
                    .background(scrum.color)
            }
        }.previewLayout(.fixed(width: 400, height: 60))   
    }   
}

If this is your model data that you may use in other views, then you may want to follow DRY and not repeat yourself by declaring the same data in all of your PreviewProviders. In that case I would make a static let of your data IN the model itself like this:

...
static let previewData = DailyScrum(
        // Initialize your data here
    )
...

and then use it in your PreviewProvider like this:

struct CardView_Previews: PreviewProvider {

    static var previews: some View {
        Group {
            ForEach(DailyScrum.previewData) { scrum in
                CardView(scrum: scrum)
                    .background(scrum.color)
            }
        }.previewLayout(.fixed(width: 400, height: 60))   
    }   
}

The way this is written assumes that DailScrum conforms to Identifiable. If it doesn't, it should, otherwise you will have to write your ForEach as ForEach(DailyScrum.previewData, id: \.self) or some other part of the model that you can use to identify the individual elements.

Yrb
  • 8,103
  • 2
  • 14
  • 44
  • The data is provided in a static array ion DailyScrum. I am just following apple's SwiftUI tutorial. The problems is definitely due to the lack of conformance to `Identifiable`, but I wonder if there is a way to achieve the same result by creating a Group from multiple previews in a for loop or ForEach without the `Identifiable` constraint. – Gael Sep 15 '21 at 11:19
0

I found the workaround I was looking for by simply adding the id argument to the ForEach initializer. It prevents from having to add Identifiable conformance to the type :

struct CardView_Previews: PreviewProvider {
    
    static var previews: some View {
        Group {
            ForEach(DailyScrum.data, id: \.title) { scrum in
                CardView(scrum: scrum)
                    .background(scrum.color)
            }
        }.previewLayout(.fixed(width: 400, height: 60))
        
    }
    
}
Gael
  • 459
  • 3
  • 18