Swift PDFKit:与 PDFView.currentDestination 和 PDFView.go 行为不一致(到目的地:PDFDestination)

问题描述 投票:0回答:2

注意: 该问题目前尚未解决;标记的答案提供了一个很好的解决方法 - 它可以在应用程序仍然打开时工作。 仍然欢迎解答!

背景

我目前正在开发一个由全屏

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

ios swift ipados ios-pdfkit
2个回答
1
投票

我在这种情况下尝试了

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
    }
}

enter image description here


0
投票

我意识到这是一篇旧帖子,但我想知道是否有人找到了完整的解决方案?

我为那些想要进一步探索这一点的人提供了我的代码。我现在认为坐标系无法正常工作,因为在转到 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)
}
© www.soinside.com 2019 - 2024. All rights reserved.