swift 如何在PDFView中禁用选择?

ghhkc1vu  于 2023-05-27  发布在  Swift
关注(0)|答案(6)|浏览(135)

PDFView中显示PDFDocument允许用户选择文档的部分并执行操作,例如:“复制”选择。如何在PDFView中禁用选择,同时保留用户在PDF中放大、缩小和滚动的可能性?
PDFView本身似乎没有提供这样的属性,PDFViewDelegate也没有。

siv3szwd

siv3szwd1#

你必须子类化PDFView,如下所示:

class MyPDFView: PDFView {

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }

    override func addGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
        if gestureRecognizer is UILongPressGestureRecognizer {
            gestureRecognizer.isEnabled = false
        }

        super.addGestureRecognizer(gestureRecognizer)
    }

}
2ledvvac

2ledvvac2#

只需要做的是它将自动清除选择和用户将不再长按PDF文本。

class MyPDFView: PDFView {

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        self.currentSelection = nil
        self.clearSelection()

        return false
    }

    override func addGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
        if gestureRecognizer is UILongPressGestureRecognizer {
            gestureRecognizer.isEnabled = false
        }

        super.addGestureRecognizer(gestureRecognizer)
    }

}

这下面2行需要在canPerformAction()中添加

self.currentSelection = nil
self.clearSelection()
zbq4xfa0

zbq4xfa03#

对于iOS 13,上述解决方案不再有效。看起来他们已经改变了PDFView的内部实现,特别是手势识别器的设置方式。我认为通常不鼓励做这种事情,但它仍然可以在不使用任何内部API的情况下完成,下面是如何做到的:
1)递归收集PDFView的所有子视图(参见下面的helper函数)

let allSubviews = pdfView.allSubViewsOf(type: UIView.self)

2)迭代它们并停用任何UILongPressGestureRecognizer s:

for gestureRec in allSubviews.compactMap({ $0.gestureRecognizers }).flatMap({ $0 }) {
    if gestureRec is UILongPressGestureRecognizer {
        gestureRec.isEnabled = false
    }
}

帮助函数可以递归地获取给定类型的所有子视图:

func allSubViewsOf<T: UIView>(type: T.Type) -> [T] {
    var all: [T] = []
    func getSubview(view: UIView) {
        if let aView = view as? T {
            all.append(aView)
        }
        guard view.subviews.count > 0 else { return }
        view.subviews.forEach{ getSubview(view: $0) }
    }
    getSubview(view: self)
    return all
}

我从包含视图控制器的viewDidLoad方法调用上面的代码。
我还没有找到一个好的方法来将其工作到PDFView的子类中,这将是可重用性的首选方法,并且可能只是对上述NonSelectablePDFView的补充。到目前为止,我所尝试的是覆盖didAddSubview并在调用super之后添加上述代码,但这并没有像预期的那样工作。看起来手势识别器只是在后面的步骤中添加的,所以弄清楚这是什么时候,以及是否有一种方法让子类在发生这种情况后调用一些自定义代码将是这里的下一步。

o2rvlv0m

o2rvlv0m4#

在Swift 5和iOS 12.3中,你可以通过覆盖PDFView子类中的addGestureRecognizer(_:)方法和canPerformAction(_:withSender:)方法来解决这个问题。

import UIKit
import PDFKit

class NonSelectablePDFView: PDFView {

    override func addGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
        (gestureRecognizer as? UILongPressGestureRecognizer)?.isEnabled = false
        super.addGestureRecognizer(gestureRecognizer)
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }

}

作为前面实现的替代方案,您可以简单地在初始化器中将UILongPressGestureRecognizerisEnabled属性切换为false

import UIKit
import PDFKit

class NonSelectablePDFView: PDFView {

    override init(frame: CGRect) {
        super.init(frame: frame)

        if let gestureRecognizers = gestureRecognizers {
            for gestureRecognizer in gestureRecognizers where gestureRecognizer is UILongPressGestureRecognizer {
                gestureRecognizer.isEnabled = false
            }
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }

}
svmlkihl

svmlkihl5#

你应该注意到,这不足以禁用文本选择,因为还有一个UITapAndHalfRecognizer--显然是一个私有的Apple类--它也会创建选择。
它被附加到PDFDocumentView,PDFDocumentView是PDFView的另一个私有实现细节,并且您不能用自己的类实现替换它。

9o685dep

9o685dep6#

在我的测试中,双击和“点击然后拖动”不会在iOS16上启用选择,但对于iOS13它会,所以这里是:
1.扩展UIViewController,添加一个函数来禁用文本选择。我把它放在UIViewController的扩展中,所以在调用它的时候,我不需要调用pdfView. recursivelyDisableSelection(view: pdfView),只要调用recursivelyDisableSelection(view: pdfView)就好了。

import UIKit
import PDFKit
extension UIViewController {

    func recursivelyDisableSelection(view: UIView) {
        
        // Get all recognizers for the PDFView's subviews. Here we are ignoring the recognizers for the PDFView itself, since we know from testing that not the reason for the mess.
        for rec in view.subviews.compactMap({$0.gestureRecognizers}).flatMap({$0}) {
            // UITapAndAHalfRecognizer is for a gesture like "tap first, then tap again and drag", this gesture also enable's text selection
            if rec is UILongPressGestureRecognizer || type(of: rec).description() == "UITapAndAHalfRecognizer" {
                rec.isEnabled = false
            }
        }
        
        // For all subviews, if they do have subview in itself, disable the above 2 gestures as well.
        for view in view.subviews {
            if !view.subviews.isEmpty {
                recursivelyDisableSelection(view: view)
            }
        }
    }
}

1.当调用函数时,传递PDFView的示例,你想禁用文本选择。注意:它应该在PDFView的文档设置之后调用,否则它将无法工作。
1.警告:如果您为PDFView启用了usePageViewController(),则在滚动以更改当前页面时,似乎会再次添加手势。一个合理的想法是为PDFViewPageChanged消息添加一个观察者,我试过了,它只在某些时候有效。一个更好的监听通知消息是PDFViewVisiblePagesChanged,这样它总是工作的。同样,观察者应该在PDFView的文档设置好之后添加,否则它将无法工作。
所以如果你像我一样使用pageViewController,你应该在两个地方调用它:每次设置文档后,此选项将禁用第一个PDFPage的选择,PDFViewVisiblePagesChanged通知中的另一个,用于后续页面滚动。

pdfView.document = `YOUR_PDF_DOCUMENT`
recursivelyDisableSelection(view: pdfView)

NotificationCenter.default.addObserver(self, selector: #selector(pageChanged), name: .PDFViewVisiblePagesChanged, object: nil)

稍后在视图控制器中,定义目标c Package 器函数:

@objc func pageChanged() {
    recursivelyDisableSelection(view: pdfView)
}

相关问题