在 Swift 开发中,打开和编辑 PDF 的系统控制器通常是 QLPreviewController
,它是 iOS 提供的一个通用文档预览控制器。通过 QLPreviewController
,你可以打开和查看 PDF 文件,甚至是其他类型的文档(如 Word、Excel 等)。
- 使用
QLPreviewController
打开 PDF 文件
如果你只是想打开和查看 PDF 文件,可以使用QLPreviewController
来实现。以下是打开 PDF 的代码示例:
示例代码(使用 QLPreviewController
打开 PDF
):
import UIKit
import QuickLook
class ViewController: UIViewController, QLPreviewControllerDataSource, QLPreviewControllerDelegate {
var documentURL: URL?
override func viewDidLoad() {
super.viewDidLoad()
// 设置 PDF 文件路径
if let pdfPath = Bundle.main.path(forResource: "sample", ofType: "pdf") {
documentURL = URL(fileURLWithPath: pdfPath)
}
// 创建并展示 QLPreviewController
let previewController = QLPreviewController()
previewController.dataSource = self
previewController.delegate = self
self.present(previewController, animated: true, completion: nil)
}
// QLPreviewControllerDataSource 方法,返回文档的数量
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
// 返回文档的 URL
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return documentURL! as QLPreviewItem
}
}
func previewControllerWillDismiss(_ controller: QLPreviewController) {
print("previewControllerWillDismiss")
}
func previewControllerDidDismiss(_ controller: QLPreviewController) {
print("previewControllerDidDismiss")
}
func previewController(_ controller: QLPreviewController, editingModeFor previewItem: any QLPreviewItem) -> QLPreviewItemEditingMode {
return .createCopy
}
func previewController(_ controller: QLPreviewController, shouldOpen url: URL, for item: any QLPreviewItem) -> Bool {
return true
}
func previewController(_ controller: QLPreviewController, didUpdateContentsOf previewItem: any QLPreviewItem) {
}
func previewController(_ controller: QLPreviewController, didSaveEditedCopyOf previewItem: any QLPreviewItem, at modifiedContentsURL: URL) {
}
QLPreviewControllerDataSource
协议是 QLPreviewController
用来获取预览内容的数据源协议。它定义了两个方法,允许开发者提供要在预览控制器中显示的项目数量和具体内容。
下面是对该协议的详细解释:
-
numberOfPreviewItems(in:)
方法描述:该方法返回预览控制器需要展示的项目数量。预览控制器将根据这个数量来显示相应的内容。
参数:
controller
:当前的QLPreviewController
实例,通常不需要在实现时使用此参数。
返回值:返回一个整数,表示预览控制器应该显示的项目数量。
可用版本:iOS 4.0 及以上
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return items.count // 返回预览项的数量
}
-
previewController(_:previewItemAt:)
方法描述:该方法返回给定索引位置的预览项。返回的预览项必须符合QLPreviewItem
协议,该协议代表一个可以被预览的对象(如文件、图片等)。
参数:
controller
:当前的QLPreviewController
实例,通常不需要在实现时使用此参数。
index
:需要返回的预览项的索引。
返回值:返回一个符合QLPreviewItem
协议的对象,通常是一个包含文件路径、URL 或本地资源的对象。
可用版本:iOS 4.0 及以上
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return items[index] // 返回指定索引位置的预览项
}
QLPreviewItem
协议
QLPreviewItem
协议是所有预览项的基协议,任何需要被 QLPreviewController
预览的对象都需要遵循该协议。
QLPreviewItem
的常见实现类:
URL
:可以是本地文件的路径或者远程文件的 URL。
文件对象
:代表需要预览的本地文件。
以下是 QLPreviewControllerDelegate
协议中各个方法的中文详细说明:
1.previewControllerWillDismiss(_:)
可用版本:iOS 4.0+
描述:该方法在 QLPreviewController
即将关闭时被调用。您可以在此方法中执行一些清理操作或准备工作。
在 QLPreviewController
关闭之前,可以执行一些必要的操作,例如保存状态或记录事件。
func previewControllerWillDismiss(_ controller: QLPreviewController) {
// 在控制器关闭前进行清理或状态保存
}
-
previewControllerDidDismiss(_:)
可用版本:iOS 4.0+
描述:该方法在QLPreviewController
关闭后被调用。适用于执行关闭后需要进行的后续操作。
可以在此方法中执行 UI 更新、状态恢复或通知其他部分的代码,表明预览已经关闭。
func previewControllerDidDismiss(_ controller: QLPreviewController) {
// 在控制器关闭后执行后续操作
}
-
previewController(_:shouldOpen:for:)
可用版本:iOS 8.0+
参数:
controller
:请求打开 URL 的QLPreviewController
实例。
url
:用户点击的URL
。
item
:与 URL 关联的QLPreviewItem
。
描述:当用户点击预览中的 URL 时,这个方法会被调用。它允许你决定是否允许QLPreviewController
打开该 URL。返回false
可以阻止QLPreviewController
打开 URL。
如果需要拦截点击事件,并根据 URL 的类型来决定是否打开,可以返回 false 来阻止打开。比如,只允许打开特定的 URL。
func previewController(_ controller: QLPreviewController, shouldOpen url: URL, for item: any QLPreviewItem) -> Bool {
// 拦截 URL,根据需求决定是否打开
if url.scheme == "myapp" {
return false
}
return true
}
-
previewController(_:frameFor:inSourceView:)
可用版本:iOS 4.0+
参数:
controller
:QLPreviewController
实例。
item
:正在预览的QLPreviewItem
。
view
:视图指针,表示点击的源视图。
描述:该方法在QLPreviewController
即将切换到全屏或从全屏模式消失时被调用。它用于提供缩放动画的初始框架。
如果你想自定义缩放效果,可以通过返回一个CGRect
来指定预览项的初始位置和大小。
func previewController(_ controller: QLPreviewController, frameFor item: any QLPreviewItem, inSourceView view: AutoreleasingUnsafeMutablePointer<UIView?>) -> CGRect {
// 自定义缩放框架
return CGRect(x: 50, y: 50, width: 200, height: 200)
}
-
previewController(_:transitionImageFor:contentRect:)
可用版本:iOS 4.0+
参数:
controller
:QLPreviewController
实例。
item
:正在预览的QLPreviewItem
。
contentRect
:指向矩形的指针,表示图像中的实际内容区域。
描述:该方法在预览控制器切换到全屏或从全屏模式返回时被调用。它允许你提供一张图像,在缩放过程中进行交叉淡入淡出动画,并且你可以指定图像中的内容矩形。
用于提供平滑的图像过渡效果。你可以返回一个缩略图或低分辨率图像,用于在缩放时交叉淡入淡出。
func previewController(_ controller: QLPreviewController, transitionImageFor item: any QLPreviewItem, contentRect: UnsafeMutablePointer<CGRect>) -> UIImage? {
return UIImage(named: "thumbnail_image") // 返回用于缩放过渡的缩略图
}
-
previewController(_:transitionViewFor:)
可用版本:iOS 10.0+
描述:该方法在QLPreviewController
切换到全屏或从全屏模式返回时被调用。它允许你返回一个自定义视图,用于过渡动画。
参数:
controller
:QLPreviewController
实例。
item
:正在预览的QLPreviewItem
。
func previewController(_ controller: QLPreviewController, transitionViewFor item: any QLPreviewItem) -> UIView? {
let transitionView = UIView()
transitionView.backgroundColor = UIColor.blue
return transitionView // 自定义过渡视图
}
-
previewController(_:editingModeFor:)
可用版本:iOS 13.0+
描述:该方法在预览控制器加载数据时被调用。它允许您指定如何处理编辑版本的预览项,例如是否允许编辑。
参数:
controller
:QLPreviewController
实例。
previewItem
:正在预览的QLPreviewItem
。
返回值:
返回一个表示如何处理编辑版本的QLPreviewItemEditingMode
枚举值。
如果允许编辑,可以返回 .updateContents 来启用更新,或者返回其他值来指定不同的处理方式。
func previewController(_ controller: QLPreviewController, editingModeFor previewItem: any QLPreviewItem) -> QLPreviewItemEditingMode {
return .updateContents // 允许更新内容
}
-
previewController(_:didUpdateContentsOf:)
方法描述:此方法会在预览控制器成功更新并覆盖文件内容时被调用,表示用户已经对文件进行了修改并保存了更改。
参数:
controller
: 当前的QLPreviewController
实例。
previewItem
: 被修改内容的QLPreviewItem
对象,即正在编辑的文件项。
功能:当用户保存编辑后的文件时,QLPreviewController
会调用此方法。特别地,这可能会多次调用,因为每当用户保存修改时,都会触发该方法。
使用场景:如果用户在QLPreviewController
中编辑了文件(如文本、文档等),每次保存编辑后,都会调用此方法来通知数据源文件内容已被更新。
@available(iOS 13.0, *)
func previewController(_ controller: QLPreviewController, didUpdateContentsOf previewItem: any QLPreviewItem) {
// 处理文件内容更新的逻辑
print("文件内容已更新:\(previewItem)")
}
-
previewController(_:didSaveEditedCopyOf:at:)
方法描述:此方法会在用户保存文件的编辑副本时被调用。这个副本是一个临时文件,可能是在编辑过程中生成的,也可能是由于内容未能直接覆盖原始文件而创建的。
参数:
controller
: 当前的QLPreviewController
实例。
previewItem
: 编辑过的原始文件项。
modifiedContentsURL
: 一个指向临时文件的 URL,该文件包含编辑后的内容。
功能:此方法会在用户保存编辑副本时触发,并且返回的是一个指向修改后内容的临时文件的 URL。此方法在以下几种情况下会被调用:
如果QLPreviewItemEditingModeCreateCopy
模式被使用(即用户创建了文件的副本)。
如果QLPreviewItemEditingModeUpdateContents
模式被使用,但原始文件无法成功覆盖,此时返回的是临时存储的编辑副本。
如果修改后的文件类型与原始文件类型不匹配(例如,编辑一个 PDF 文件后另存为图片格式),此时返回的副本可能是不同类型的文件。
使用场景:当用户保存修改的副本时,例如文本编辑应用允许用户修改文件并保存编辑副本,或者当修改文件后无法直接覆盖原始文件时,都会调用此方法。
@available(iOS 13.0, *)
func previewController(_ controller: QLPreviewController, didSaveEditedCopyOf previewItem: any QLPreviewItem, at modifiedContentsURL: URL) {
// 处理保存的副本
print("文件的编辑副本已保存:\(modifiedContentsURL)")
}