1

我正在使用 PDF 工具包库在 PDF 视图上加载一个 PDF。我在 pdf 视图上添加了一个自定义视图(与 PDF 注释相同),并且我允许用户使用 UIPanGestureRecognizer 在 pdf 视图(在 pdf 视图/容器视图中)移动/拖动该自定义视图。这是一个gif,

在此处输入图像描述

如果您看到此 gif,则存在一个问题。该自定义视图超出了 pdf 页面。我想限制它。自定义视图应仅在 pdf 页面内移动/拖动。我该如何解决这个问题?有解决办法吗?

这是链接示例项目和所有代码 - https://drive.google.com/file/d/1Ilhd8gp4AAxB_Q9G9swFbe4KQUHbpyGs/view?usp=sharing

这是项目中的一些代码示例,

override func didMoveToSuperview() {
        addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(pan)))
    }

@objc func pan(_ gesture: UIPanGestureRecognizer) {
    translate(gesture.translation(in: self))
    gesture.setTranslation(.zero, in: self)
    setNeedsDisplay()
    print("Frames after moving : \(frame)")
}

和用作扩展的代码

extension  CGPoint {
    static func +(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
        .init(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
    }
    static func +=(lhs: inout CGPoint, rhs: CGPoint) {
        lhs.x += rhs.x
        lhs.y += rhs.y
    }
}
extension UIView {
    func translate(_ translation: CGPoint) {
        let destination = center + translation
        let minX = frame.width/2
        let minY = frame.height/2
        let maxX = superview!.frame.width-minX
        let maxY = superview!.frame.height-minY
        center = CGPoint(
            x: min(maxX, max(minX, destination.x)),
            y: min(maxY ,max(minY, destination.y)))
    }
}

代码 - 获取 PDF 页面高度和宽度

 let page = pdfDocument.page(at: 0)
 let pageRect = page?.bounds(for: .mediaBox)

 print("pdf page width =", (pageRect?.size.width)!, "pdf page height =", (pageRect?.size.height)!)
4

1 回答 1

3

我建议PDFAnnotationUIView内容添加到PDFView.

由于它们的坐标系不同,因此比较 aUIView's内的框架并不容易。PDFView

PDFAnnotation在与 PDF 坐标系同步的作品中添加 aPDFView在使用 UIView 时,您将需要在坐标空间之间进行一些转换,这可能会很棘手而且不太准确。

PDFKit PDFView 坐标系添加 PDF Annotation UIView

以下是我为使其与视图一起工作而进行的一些小改动。

首先在你SignatoryXibView我添加了这个功能,当我们靠近边缘时显示一个红色边框

func showWarning(_ show: Bool)
{
    if show
    {
        contentView1.layer.borderColor = UIColor.red.cgColor
        return
    }
    
    contentView1.layer.borderColor = UIColor.green.cgColor
}

我认为SignatoryXibView不应该负责检测和防止超出其超级视图范围,因此我创建了一个 ViewController 需要遵守的协议,以便它可以防止SignatoryXibView超出PDFView范围。

protocol SignatoryViewDelegate: class
{
    func signatoryView(_ signatoryView: SignatoryXibView,
                       didReceivePanGesture gesture: UIPanGestureRecognizer)
}

class SignatoryXibView: UIView {

    // Add this
    weak var delegate: SignatoryViewDelegate?
    
    // .. rest of your code
    
    @objc
    func pan(_ gesture: UIPanGestureRecognizer)
    {
        // Hand off view translation handling to the delegate
        self.delegate?.signatoryView(self,
                                     didReceivePanGesture: gesture)
    }
}

现在在您的UIView扩展程序中,您创建了一个效果很好的翻译方法,但是您不想翻译视图的位置。您要首先检查翻译是否会超出所需的边界并防止翻译发生。

extension UIView {
    
    // Your original code
    func translate(_ translation: CGPoint) {
        let destination = center + translation
        let minX = frame.width/2
        let minY = frame.height/2
        let maxX = superview!.frame.width-minX
        let maxY = superview!.frame.height-minY
        center = CGPoint(
            x: min(maxX, max(minX, destination.x)),
            y: min(maxY ,max(minY, destination.y)))
    }
    
    // I have added this function to return the new rect
    // that would happen if this view translated
    func translatedRect(_ translation: CGPoint) -> CGRect
    {
        // All of this is your calculation
        let destination = center + translation
        
        let minX = frame.width/2
        let minY = frame.height/2
        let maxX = superview!.frame.width-minX
        let maxY = superview!.frame.height-minY
        
        var rect = CGRect(origin: .zero,
                          size: CGSize(width: bounds.width,
                                       height: bounds.height))
        
        let midX = min(maxX, max(minX, destination.x))
        let midY = min(maxY ,max(minY, destination.y))
        
        // I am not translating here, just creating a new rect
        // of the view if it would be translated
        rect.origin = CGPoint(x: midX - frame.width/2,
                              y: midY - frame.height/2)
        
        return rect
    }
}

在您的ViewController's loadPDF()函数中,使您的视图控制器成为SignatoryXibView

// Add Sign on PdfView
// Your code unchanged
let customView = SignatoryXibView(frame: CGRect(x: 150, 
                                                y: 140, 
                                                width: 112, 
                                                height: 58))
customView.signatoryLabel.text = "John Doe"
self.pdfView.addSubview(customView)

//Add this
customView.delegate = self

然后最后实现我们之前在协议中添加的委托函数,以防止SignatoryXibView超出页面边界。

extension ViewController: SignatoryViewDelegate
{
    func signatoryView(_ signatoryView: SignatoryXibView,
                       didReceivePanGesture gesture: UIPanGestureRecognizer)
    {
        // Get the location where the user has tapped
        let gestureTouchLocation = gesture.translation(in: signatoryView)
        
        // Get the new frame if the signature view would
        // be translated
        let updatedFrame
            = signatoryView.translatedRect(gestureTouchLocation)
        
        // Convert this rect from the Signature View's coordinate space
        // To the PDFView's coordinate space
        let updatedFrameConverted
        = pdfView.convert(updatedFrame,
                          to: pdfView.currentPage!)
        
        print("Updated frame: \(updatedFrame)")
        print("Updated frame converted: \(updatedFrameConverted)")
        print("Signature frame: \(signatoryView.frame)")
        print()
        
        // Retrieve the bounds of the current page
        // Handle the optional properly in your production app
        let pageRect = pdfView.currentPage!.bounds(for: .mediaBox)
        
        // Check if the new frame of SignatoryXibView is within the bounds of the pdf page
        if updatedFrameConverted.origin.x > CGFloat.zero &&
            updatedFrameConverted.origin.y + updatedFrameConverted.height < pageRect.height &&
            updatedFrameConverted.origin.x + updatedFrameConverted.width < pageRect.width &&
            updatedFrameConverted.origin.y > CGFloat.zero
        
        {
            // Since the view is within the bounds, you can update the views frame
            
            signatoryView.translate(gesture.translation(in: signatoryView))
            
            gesture.setTranslation(.zero, in: signatoryView)
            signatoryView.setNeedsDisplay()
            
            
            
            // Do not show any warning
            signatoryView.showWarning(false)
            
            return
        }
        
        // The view has reached the edge of the page so do not perform any view
        // translation and show the warning
        signatoryView.showWarning(true)
    }
}

最终结果应该为您提供以下结果,它可以防止视图超出页面边界并使视图变为红色以显示它无法进一步:

PDFKit PDFView 防止注释边界 UIView 边距

最后的想法

  1. 我建议PDFAnnotation在向 PDF 添加内容时使用
  2. 这将正确缩放和滚动页面,尤其是在缩放 PDF 等场景中,您可能需要再次更新视图以使其位于正确的位置

更新

func signatoryView我在函数中更新了一些数学extension ViewController: SignatoryViewDelegate

在确定正确的边界方面,这应该会给您带来更好的结果,并且在您缩放时它也会起作用:

PDFView UIView 边界注释页面宽度页面高度

但是,由于它不是作为注释添加的,因此它不会随页面滚动,但在下一页上会观察到相同的边界。

于 2022-02-09T04:28:48.797 回答