Mostrar un PDFDocument en un PDFView permite al usuario seleccionar partes del documento y realizar acciones, p. "copiar" con la selección. ¿Cómo se puede deshabilitar la selección en un PDFView mientras se conserva la posibilidad de que el usuario acerque y aleje y se desplace en el PDF?

PDFView en sí mismo no parece ofrecer tal propiedad ni el PDFViewDelegate.

9
chriswillow 4 mar. 2018 a las 22:28

5 respuestas

La mejor respuesta

Tienes que subclasificar PDFView, como tal:

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

}
7
AamirR 4 mar. 2018 a las 20:02

Para iOS 13, la solución anterior ya no funciona. Parece que han cambiado la implementación interna de PDFView y específicamente cómo se configuran los reconocedores de gestos. Creo que, en general, se desaconseja hacer este tipo de cosas, pero aún se puede hacer sin usar ninguna API interna, así es como:

1) Reúna recursivamente todas las subvistas de PDFView (vea a continuación la función de ayuda para hacer esto)

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

2) Iterar sobre ellas y desactivar cualquier UILongPressGestureRecognizer s:

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

Función de ayuda para obtener recursivamente todas las subvistas de un tipo dado:

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
}

Llamo al código anterior desde el método viewDidLoad del controlador de vista que lo contiene.

Todavía no he encontrado una buena manera de trabajar esto en una subclase de PDFView, que sería la forma preferida de reutilización y podría ser una adición a la NonSelectablePDFView anterior. Lo que he intentado hasta ahora es anular didAddSubview y agregar el código anterior después de la llamada a super, pero eso no funcionó como se esperaba. Parece que los reconocedores de gestos solo se agregarán en un paso posterior, por lo que averiguar cuándo es eso y si hay una forma para que la subclase llame a un código personalizado después de que esto sucediera sería el siguiente paso aquí.

2
julsh 1 oct. 2019 a las 14:43

Solo es necesario que se borre automáticamente la selección y el usuario ya no mantenga presionado el texto 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)
    }

}

Esto debajo de 2 líneas necesita agregar canPerformAction ()

self.currentSelection = nil
self.clearSelection()
2
Darshit Mendapara 24 feb. 2020 a las 13:44

Debe tener en cuenta que esto no es suficiente para deshabilitar la selección de texto, ya que también hay un UITapAndHalfRecognizer, obviamente una clase privada de Apple, que también crea selecciones.

Se adjunta a PDFDocumentView, que es otro detalle de implementación privada de PDFView, y que no puede reemplazar con su propia implementación de clase.

0
Klaus Busse 17 ene. 2020 a las 11:52

Con Swift 5 y iOS 12.3, puede resolver su problema anulando {{X0} } método y canPerformAction(_:withSender:) en una subclase PDFView.

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
    }

}

Como alternativa a la implementación anterior, simplemente puede alternar la propiedad UILongPressGestureRecognizer isEnabled a false en el inicializador.

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
    }

}
2
Imanou Petit 3 jul. 2019 a las 12:41