限制在 PDF 页面边界内移动/拖动 pdf 注释

2023-12-15

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

如果你看到这张动图,那就有问题了。该自定义视图位于 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)!)

我会推荐PDFAnnotation比较起来UIView用于将内容添加到PDFView.

比较一个并不那么容易UIView's框架内的PDFView由于它们的坐标系不同。

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

PDFKit PDFView coordinate system add 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 bounds.

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

In your 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 prevent Annotation boundary UIView margins

最后的想法

  1. 我建议使用PDFAnnotation将内容添加到 PDF 时
  2. 这将正确缩放和滚动页面,特别是在缩放 PDF 等情况下,您可能需要再次更新视图才能使其位于正确的位置

Update

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

这应该会给你更好的结果来找出正确的边界,并且当你缩放时它也会起作用:

PDFView UIView boundary annotation page width page height

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

限制在 PDF 页面边界内移动/拖动 pdf 注释 的相关文章

随机推荐