限制 move/drag PDF 页面边界内的 pdf 注释
Restrict to move/drag the pdf annotation within PDF Page boundary
我正在使用 PDF 套件库在 PDF 视图中加载一个 PDF。我在 pdf 视图上添加了一个自定义视图(与 PDF 注释相同),我允许用户使用 UIPanGestureRecognizer move/drag 在 pdf 视图(在 pdf view/container 视图中)自定义视图。
这是一张动图,
如果您看到这张 gif,说明有一个问题。该自定义视图超出了 pdf 页面。我想限制它。自定义视图应仅在 pdf 页面内 move/drag。
我该如何解决这个问题?有解决办法吗?
这是 link 示例项目和所有代码 - 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
添加到 PDFView
与 PDF 坐标系同步工作,而使用 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)
}
}
最终结果应为您提供以下结果,该结果可防止视图超出页面边界并使视图变红以表明它无法继续前进:
最后的想法
- 我建议在向 PDF 添加内容时使用
PDFAnnotation
- 这将正确缩放和滚动页面,尤其是在缩放 PDF 等场景中,您可能需要再次更新视图以使其位于正确的位置
更新
我在 extension ViewController: SignatoryViewDelegate
的 func signatoryView
函数中更新了一些数学运算
这应该会在确定正确边界方面为您提供更好的结果,并且在您缩放时它也会起作用:
但是,由于没有添加为注释,因此不会随页面滚动,但在下一页会观察到相同的边界。
我正在使用 PDF 套件库在 PDF 视图中加载一个 PDF。我在 pdf 视图上添加了一个自定义视图(与 PDF 注释相同),我允许用户使用 UIPanGestureRecognizer move/drag 在 pdf 视图(在 pdf view/container 视图中)自定义视图。 这是一张动图,
如果您看到这张 gif,说明有一个问题。该自定义视图超出了 pdf 页面。我想限制它。自定义视图应仅在 pdf 页面内 move/drag。 我该如何解决这个问题?有解决办法吗?
这是 link 示例项目和所有代码 - 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
添加到 PDFView
与 PDF 坐标系同步工作,而使用 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)
}
}
最终结果应为您提供以下结果,该结果可防止视图超出页面边界并使视图变红以表明它无法继续前进:
最后的想法
- 我建议在向 PDF 添加内容时使用
PDFAnnotation
- 这将正确缩放和滚动页面,尤其是在缩放 PDF 等场景中,您可能需要再次更新视图以使其位于正确的位置
更新
我在 extension ViewController: SignatoryViewDelegate
func signatoryView
函数中更新了一些数学运算
这应该会在确定正确边界方面为您提供更好的结果,并且在您缩放时它也会起作用:
但是,由于没有添加为注释,因此不会随页面滚动,但在下一页会观察到相同的边界。