Is there a delegate method that gets called before the UIDocumentInteractionController share sheet pop ups
Please can someone help.I would like to add an alert message once a user clicks on the share button on a pdf viewer, i'm using UIDocumentInteractionController to preview the pdf document. and i wanted to know if there are any delegate methods or functions that i can override, where i can add my alert before opening the sharing sheet?[![enter image description here][1]][1]
class ViewController: UIViewController {
var documentController : UIDocumentInteractionController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction private func buttonTapped(_ sender: Any) {
guard let fileURL = Bundle.main.url(forResource: "infomation", withExtension: "pdf") else {return}
documentController = UIDocumentInteractionController.init(url: fileURL)
documentController.delegate = self
documentController.presentPreview(animated: true)
}
}
extension ViewController: UIDocumentInteractionControllerDelegate {
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}
func documentInteractionControllerWillPresentOpenInMenu(_ controller: UIDocumentInteractionController) {
}
func documentInteractionControllerWillPresentOptionsMenu(_ controller: UIDocumentInteractionController) {
}
func documentInteractionController(_ controller: UIDocumentInteractionController, willBeginSendingToApplication application: String?) {
}
}
but none of them get called when i click on the share button, even though i have set the delegate to be my view controller.is there a way that i can do this ?
Solution 1:
Explanation:
There isn't a way to do that without hacking it together by iterating all the sub-views and override the button's action and target.
One clean way is to create your own preview controller like shown below. If you add the QLPreviewController
to UINavigationController
, it will automatically create a bottom toolbar
which you don't want. To work around this, you add it as a child controller of a regular UIViewController
and create a custom navigation bar.
You can also use the UTI
for the UIActivityItem
to determine how the item can be shared. I've only implemented the preview and basic sharing capabilities, but the rest should be super easy to do, and at least it's more customizable than UIDocumentInteractionController
since you have full control of everything.
Now for the code that does all of this:
//
// ViewController.swift
// CustomDocumentController
//
// Created by brandon on 2022-01-13.
//
import UIKit
import QuickLook
import MobileCoreServices
import UniformTypeIdentifiers
private class PreviewItem: NSObject, QLPreviewItem {
var previewItemURL: URL?
var previewItemTitle: String?
init(title: String, url: URL) {
super.init()
previewItemURL = url
previewItemTitle = title
}
}
class DocumentInteractionController: UIViewController {
private let url: URL
private lazy var navigationBar: UINavigationBar = {
let navigationBar = UINavigationBar()
let navigationItem = UINavigationItem(title: name ?? "Document")
navigationItem.hidesBackButton = true
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(onDone))
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(onShare)) //UIImage(systemName: "square.and.arrow.up")
navigationBar.pushItem(navigationItem, animated: false)
return navigationBar
}()
private lazy var previewController: QLPreviewController = {
let previewController = QLPreviewController()
previewController.title = name
previewController.dataSource = self
previewController.delegate = self
previewController.reloadData()
return previewController
}()
var uti: String? {
didSet {
previewController.reloadData()
}
}
var name: String? {
didSet {
previewController.title = name
navigationBar.topItem?.title = name
}
}
init(url: URL) {
self.url = url
super.init(nibName: nil, bundle: nil)
//super.init(rootViewController: self.previewController)
self.modalPresentationStyle = .fullScreen
name = (try? url.resourceValues(forKeys: [.localizedNameKey]))?.localizedName
uti = (try? url.resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
if uti == nil {
if #available(iOS 15.0, *) {
uti = UTType.url.identifier
} else {
uti = String(kUTTypeURL)
}
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
addChild(previewController)
previewController.didMove(toParent: self)
let separator = UIView()
separator.backgroundColor = .lightGray
view.addSubview(navigationBar)
view.addSubview(separator)
view.addSubview(previewController.view)
NSLayoutConstraint.activate([
navigationBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
navigationBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
separator.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
separator.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
separator.topAnchor.constraint(equalTo: navigationBar.bottomAnchor),
separator.heightAnchor.constraint(equalToConstant: 1.0 / UIScreen.main.scale),
previewController.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
previewController.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
previewController.view.topAnchor.constraint(equalTo: separator.bottomAnchor),
previewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
[navigationBar, separator, previewController.view].forEach({
$0?.translatesAutoresizingMaskIntoConstraints = false
})
navigationBar.barTintColor = previewController.view.backgroundColor
view.backgroundColor = previewController.view.backgroundColor
}
}
extension DocumentInteractionController: QLPreviewControllerDelegate, QLPreviewControllerDataSource {
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return PreviewItem(title: name ?? "Document", url: url)
}
}
extension DocumentInteractionController {
@objc
private func onDone() {
self.dismiss(animated: true, completion: nil)
}
@objc
private func onShare() {
let activityViewController = UIActivityViewController(activityItems: [url],
applicationActivities: nil)
activityViewController.excludedActivityTypes = [.assignToContact]
if UIDevice.current.userInterfaceIdiom == .pad {
activityViewController.popoverPresentationController?.sourceView = self.view
}
self.present(activityViewController, animated: true, completion: nil)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "Testing", withExtension: ".md")
let doc = DocumentInteractionController(url: url!)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.present(doc, animated: true, completion: nil)
}
}
}
Screenshots: