注意: 该问题目前尚未解决;标记的答案提供了一个很好的解决方法 - 它可以在应用程序仍然打开时工作。 仍然欢迎解答!
背景
我目前正在开发一个由全屏
PDFView
组成的应用程序,我希望程序在视图被关闭之前记住文档中的位置,以便用户可以从离开的地方继续。
实施
该应用程序的简化版本可以理解为使用
PDFKit.PDFView
的 PDF 查看器。 Storyboard 由连接到 PDFView 类 DocumentView
(符合 UIViewController
)的 UIView 组成。视图通过以下过程初始化:
在
viewDidLoad
:
let PDF: PDFDocument = GetPDFFromServer()
DocumentView.document = PDF!
DocumentView.autoScales = true
... (other settings)
// Set PDF Destination
let Destination: PDFDestination = GetStoredDestination()
// Code with issues
DocumentView.go(to: Destination)
在
viewWillDisappear
:
StoreDestination(DocumentView.currentDestination)
问题与测试
我意识到代码没有按预期工作;视图不会返回到之前的位置。
通过调试,我意识到这可能是由于
DocumentView.go(to destination: PDFDestination)
和DocumentView.currentDestination
行为不一致造成的。
为了确保存储位置时不会因错误而引入bug,使用以下代码来验证问题,并附有多页文档:
在
viewDidLoad
Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
DispatchQueue.main.async {
self.DocumentView.go(to:self.DocumentView.currentDestination!)
}
})
预期和观察到的行为
预期:文档的位置不应更改 - 代码每 1 秒就会转到当前目的地,这应该不会产生任何影响。因为“currentDestination”应该是“文档的当前目的地,每个文档”)
观察到:执行后,页面会自发地向下滚动固定偏移量。
在 iPadOS 14.5 模拟器和 iPadOS 15 iPad Air(第 4 代)上观察到相同的结果。
可能出了什么问题?
如果有人能帮忙那就太好了。
干杯, 林肯
这个问题最初发布在一周多前的Apple开发者论坛上;一个多星期没有收到任何回复,所以我想我可以在 StackOverflow 上碰碰运气 <3
我在这种情况下尝试了
PDFView.go()
,并设法让它在某些情况下工作,但发现它在其他一些情况下失败,例如缩放文档、更改方向。
那么回到你想要实现的目标,
我目前正在开发一个由全屏组成的应用程序 PDFView,我希望程序记住在 视图被关闭之前的文档,以便用户可以选择 他们已经离开了。
这可以通过不同的方法来完成。使用这种方法,您需要始终保留对您创建的
PDFView
的引用。如果需要再次加载以前的 pdf,则将您拥有的 PDFView
实例按原样传递给 viewController
。否则,您将新的 pdf 加载到 PDFView
实例并将其传递给 viewController
。
DocumentViewController
在初始化时获取PDFView
。
import UIKit
import PDFKit
protocol DocumentViewControllerDelegate: AnyObject {
func needsContinuePDF(continuePDF: Bool)
}
class DocumentViewController: UIViewController {
var pdfView: PDFView!
weak var delegate: DocumentViewControllerDelegate!
init(pdfView: PDFView, delegate: DocumentViewControllerDelegate){
self.pdfView = pdfView
self.delegate = delegate
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
self.view.backgroundColor = .white
view.addSubview(pdfView)
NSLayoutConstraint.activate([
pdfView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
pdfView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
override func viewWillDisappear(_ animated: Bool) {
delegate.needsContinuePDF(continuePDF: true)
}
}
您可以像下面这样初始化
DocumentViewController
。 MainViewController
负责初始化 PDFView
。
import UIKit
import PDFKit
class MainViewController: UIViewController {
var pdfView: PDFView = PDFView()
var continuePreviousPDF = false
let button = UIButton(frame: .zero)
override func loadView() {
super.loadView()
button.setTitle("View PDF", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemBlue
button.addTarget(self, action: #selector(openDocumentView(_:)), for: .touchUpInside)
self.view.backgroundColor = .systemGray5
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalToConstant: 100),
button.heightAnchor.constraint(equalToConstant: 50),
button.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor),
button.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor),
])
}
@objc func openDocumentView(_ sender: UIButton) {
//open a nee PDF if not continue previous one
if !self.continuePreviousPDF {
pdfView.autoScales = true
pdfView.displayMode = .singlePageContinuous
pdfView.translatesAutoresizingMaskIntoConstraints = false
guard let path = Bundle.main.url(forResource: "sample copy", withExtension: "pdf") else { return }
if let document = PDFDocument(url: path) {
pdfView.document = document
}
}
let documentViewController = DocumentViewController(pdfView: pdfView, delegate: self)
self.present(documentViewController, animated: true, completion: nil)
}
}
extension MainViewController: DocumentViewControllerDelegate {
func needsContinuePDF(continuePDF: Bool) {
self.continuePreviousPDF = continuePDF
}
}
我意识到这是一篇旧帖子,但我想知道是否有人找到了完整的解决方案?
我为那些想要进一步探索这一点的人提供了我的代码。我现在认为坐标系无法正常工作,因为在转到 currentDestination 然后保存 currentDestination 后, currentDestination 值是相同的。或者也许还有一些苹果开发人员没有提到的额外内部“修正”。
// Enum to define the state actions
enum ePDFViewState {
case save
case restore
}
// Struct to store the PDFView state
struct PDFViewState {
var pageIndex: Int?
var zoom: CGFloat?
var location: CGPoint?
}
// Global variable to hold the state
var savedPDFViewState = PDFViewState()
func pdfViewState(state: ePDFViewState, for pdfView: PDFView) {
switch state {
case .save:
guard let currentDestination = pdfView.currentDestination,
let document = pdfView.document else {
print("Failed to get the current destination or document")
return
}
// Save the destination parameters
let currentPage = currentDestination.page!
let pageIndex = document.index(for: currentPage)
let zoom = currentDestination.zoom
let location = currentDestination.point
savedPDFViewState = PDFViewState(pageIndex: pageIndex, zoom: zoom, location: location)
print("State saved:")
print("page index: \(pageIndex)")
print("zoom: \(zoom)")
print("location: \(location)")
case .restore:
guard let document = pdfView.document,
let pageIndex = savedPDFViewState.pageIndex,
let location = savedPDFViewState.location,
let zoom = savedPDFViewState.zoom else {
print("Failed to restore the destination state")
return
}
// Restore the destination parameters
let restoredPage = document.page(at: pageIndex)!
let restoredDestination = PDFDestination(page: restoredPage, at: location)
restoredDestination.zoom = zoom
pdfView.go(to: restoredDestination)
print("State restored:")
print("page index: \(pageIndex)")
print("zoom: \(zoom)")
print("location: \(location)")
}
}
func loadDoc() {
guard let fileURL = Bundle.main.url(forResource: String("mydoc"), withExtension: "pdf") else { print(" error "); return }
pdfView.document = PDFDocument(url: fileURL)
}
func test() {
// loadDoc was called on ViewWillAppear()
// scroll & zoom
pdfViewState(state: .save, for: pdfView)
loadDoc()
pdfViewState(state: .restore, for: pdfView)
}