PreviewProvider doesn't work in Widget Extension

Viewed 391

I have this view

import SwiftUI

struct CurrentOrderView: View {
  let order: CurrentOrder

  var body: some View {
    VStack(alignment: .leading, spacing: 4) {
      HStack {
        Text("Order:")
        Text(order.orderId)
      }

      HStack {
        Image(uiImage: deliveryImage)
          .resizable()
          .aspectRatio(contentMode: .fit)
          .frame(width: 50.0, height: 50.0)
        Text(order.formattedDeliveryTimeString)
      }
    }
    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading)
    .padding()
    .background(LinearGradient(gradient: Gradient(colors: [.orange, .yellow]), startPoint: .top, endPoint: .bottom))
  }
}

// MARK: - Private

private extension CurrentOrderView {
  private var deliveryImage: UIImage {
    switch order.status {
    case .driverOnTheWayToRestaurant:
      return UIImage(named: "pin-restaurant") ?? UIImage()
    case .driverOnTheWayToUser:
      return UIImage(named: "rider") ?? UIImage()
    }
  }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      CurrentOrderView(
        order: CurrentOrderEntryPlaceholderBuilder()
          .entry(with: .snapshot).order
      )
      .previewLayout(.fixed(width: 200, height: 100))
    }
  }
}
#endif

In canvas I see:

enter image description here

3 Answers

Instead of using previewLayout, use WidgetPreviewContext

The following would add a preview for a medium widget. .systemMedium can also be .systemSmall and .systemLarge

#if DEBUG
struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      CurrentOrderView(
        order: CurrentOrderEntryPlaceholderBuilder()
          .entry(with: .snapshot).order
      )
      .previewContext(WidgetPreviewContext(family: .systemMedium))
    }
  }
}
#endif

Add previewContext to your PreviewProvider

#if DEBUG
struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      CurrentOrderView(
        order: CurrentOrderEntryPlaceholderBuilder()
          .entry(with: .snapshot).order
      )
      .previewContext(WidgetPreviewContext(family: .systemMedium))
    }
  }
}
#endif

It looks like you don't want to preview a widget but just a view.

What you can do is to move CurrentOrderView and its Entry to another file.

Then add this file to the main App target (apart from the Widget target).

Also make sure to rename previews struct, so the name is different than the auto-generated ContentView_Previews previews.

This way your previews will work as expected:

struct CurrentOrderView_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      CurrentOrderView(
        order: CurrentOrderEntryPlaceholderBuilder()
          .entry(with: .snapshot).order
      )
      .previewLayout(.fixed(width: 200, height: 100))
    }
  }
}
Related