Search code examples
iosobjective-ciphonexcodeuidocumentpickerviewcontroller

How to preview multiple PDF files in iOS similar to WhatsApp upload documents functionality?


I am integrating UIDocumentPickerViewController to show the local storage (File App) for browsing and selecting the PDF. Right now i am selecting a single PDF and previewing it by passing the URL to WKWebview which is working fine. But when i enable allowsMultipleSelection i am able to select the multiple files and getting multiple URLs

NSArray *types = @[(NSString*)kUTTypePDF];
//Create a object of document picker view and set the mode to Import
UIDocumentPickerViewController *docPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:types inMode:UIDocumentPickerModeImport];
//Set the delegate
docPicker.delegate = self;
docPicker.allowsMultipleSelection = true; // Allows multiple selection.
//present the document picker
[self presentViewController:docPicker animated:YES completion:nil];

The delegate for getting multiple URLs is :

- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls API_AVAILABLE(ios(11.0));

while previewing using WKWebView i am able to preview only one file as shown below:

But i want to preview both the selected files as WhatsApp does as shown below. Here i can swipe horizontally to preview the selected files

How to preview multiple files similar to WhatsApp? Please help me in this regard.


Solution

  • Use a QLPreviewController; you'll need to import QuickLook. It's a view controller. You show it as a presented view controller or push it onto a navigation controller's stack.

    In this example, I have somewhere in my Documents directory one or more PDF or text documents. I acquire a list of their URLs and present a preview for them (self.exts has been initialized to a set consisting of ["pdf", "txt"]):

    self.docs = [URL]()
    do {
        let fm = FileManager.default
        let docsurl = try fm.url(for:.documentDirectory, 
            in: .userDomainMask, appropriateFor: nil, create: false)
        let dir = fm.enumerator(at: docsurl, includingPropertiesForKeys: nil)!
        for case let f as URL in dir {
            if self.exts.contains(f.pathExtension) {
                if QLPreviewController.canPreview(f as QLPreviewItem) {
                    self.docs.append(f)
                }
            }
        }
        guard self.docs.count > 0 else { return }
        let preview = QLPreviewController()
        preview.dataSource = self
        preview.currentPreviewItemIndex = 0
        self.present(preview, animated: true)
    } catch {
        print(error)
    }
    

    You'll notice that I haven't told the QLPreviewController what documents to preview. That is the job of QLPreviewController's data source. In my code, I (self) am also the data source. I simply fetch the requested information from the list of URLs, which I previously saved into self.docs:

    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
        return self.docs.count
    }
    func previewController(_ controller: QLPreviewController, 
        previewItemAt index: Int) -> QLPreviewItem {
            return self.docs[index] as QLPreviewItem
    }
    

    The second data source method requires us to return an object that adopts the QLPreviewItem protocol. URL does adopt this protocol.