繁体   English   中英

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

[英]Restrict to move/drag the pdf annotation within PDF Page boundary

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

如果您看到此 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)!)

我会推荐PDFAnnotation而不是UIView来将内容添加到PDFView

由于坐标系不同,在PDFView中比较UIView's框架并不容易。

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

PDFKit PDFView坐标系添加PDF Annotation UIView

这里有一些我所做的小改动,以使其与视图一起工作。

首先,在您的SignatoryXibView中,我添加了这个 function 以在我们靠近边缘时显示红色边框

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扩展中,您创建了一个运行良好的翻译方法,但是您不想翻译视图的位置。 您首先要检查翻译是否 go 超出所需边界并防止翻译发生。

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() function 中,使您的视图 controller 成为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

最后,您将实现我们之前在协议中添加的委托 function,以防止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)
    }
}

最终结果应该给你下面的结果,它防止视图超出页面边界并使视图变红以显示它不能进一步 go:

PDFKit PDFView 防止 Annotation 边界 UIView 边距

最后的想法

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

更新

我在extension ViewController: SignatoryViewDelegatefunc signatoryView function 中更新了一些数学:SignatoryViewDelegate

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

PDFView UIView 边界注解页宽页高

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM