Search code examples
iosswiftswiftuiswiftui-tabviewqlpreviewcontroller

Why doesn't QLPreviewController work in SwiftUI TabView?


I cannot find a way to get QuickLook(QLPreviewController) to load a pdf inside of a SwiftUI TabView. Is there a way to make this work? It is specifically when I tell Tabview to be a .page View.

struct QuickLookView: View {
    @State private var url: URL = Bundle.main.url(forResource: "Sample-PDF", withExtension: "pdf")!
    @State private var tab: Int = 0
    var body: some View {
        NavigationStack {
            TabView(selection: $tab) {
                ForEach(0..<3) { num in
                    PreviewController(url: url).tag(num)
                }
            }
            .tabViewStyle(.page(indexDisplayMode: .never))
        }
    }
}
struct PreviewController: UIViewControllerRepresentable {
    let url: URL
    
    func makeUIViewController(context: Context) -> QLPreviewController {
        let controller = QLPreviewController()
        controller.dataSource = context.coordinator
        return controller
    }
    
    func updateUIViewController(
        _ uiViewController: QLPreviewController, context: Context) {}
    
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, QLPreviewControllerDataSource, UIGestureRecognizerDelegate {
        
        let parent: PreviewController
        
        init(parent: PreviewController) {
            self.parent = parent
        }
        
        func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
            return 1
        }
        
        func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
            return parent.url as NSURL
        }
    }
}

Solution

  • Very curious. It works when you wrap your PreviewController in a NavigationStack like this:

    struct QuickLookView: View {
        @State private var url: URL = Bundle.main.url(forResource: "Sample-PDF", withExtension: "pdf")!
        @State private var tab: Int = 0
        
        var body: some View {
            TabView(selection: $tab) {
                ForEach(0..<3) { num in
                    NavigationStack {
                        PreviewController(url: url)
                    }   .tag(num)
                }
                
            }   .tabViewStyle(.page(indexDisplayMode: .never))
        }
    }
    

    Unfortunately, if you then add a NavigationStack to contain the TabView it stops working again. I hope someone else can shed some more light on this weird behaviour. You may want to file a bug at Apple.