如何解决PDF View和SCrollView的手势冲突 [Swift 5, iOS 14]
How to resolve the conflict of gestures between PDFView and SCrollView [Swift5, iOS 14]
我正在为 iPad 创建一个 PDF 查看器,用户可以使用它通过水平滚动来阅读 PDF。
我创建了以下代码来实现通过手势更改页面的单页视图(同时咨询 How to create a single page vertical scrolling PDFView in Swift 和其他地方)。
尽管这种方法在大多数情况下都可以正常工作,但我发现在放大 PDF 文件时无法检测到(或调用)手势。因此,我无法通过滑动屏幕转到下一页。使用我创建的 extension PDFView {}
函数,我发现禁用 subview
中的用户交互可以让我检测到滑动手势。但是,现在我无法在 PDFView
内滚动页面。如果你能帮我弄清楚如何解决这个问题,我将不胜感激。
我想实现的是类似 PDF Expert
(https://apps.apple.com/us/app/pdf-expert-pdf-reader-editor/id743974925) 的东西,我可以在其中水平滚动到下一页。
非常感谢您的提前帮助!
import UIKit
import PDFKit
//PDF Zoom scale
var scaleOfPdf: CGFloat = 4
extension PDFView {
func disableBouncing(){
for subview in subviews{
if let scrollView = subview as? UIScrollView{
scrollView.bounces = false
return
}
}
class ViewController: UIViewController, UIGestureRecognizerDelegate, UIDocumentPickerDelegate {
@IBOutlet weak var pdfView: PDFView!
override func viewDidLoad(){
super.viewDidLoad()
pdfView.autoresizesSubviews = true
pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleLeftMargin]
pdfView.displayDirection = .horizontal
pdfView.displayMode = .singlePage
pdfView.autoScales = true
// setting a color for background
pdfView.backgroundColor = .black
pdfView.document = pdfDocument
// pdfView.usePageViewController(true, withViewOptions: [UIPageViewController.OptionsKey.interPageSpacing: 20])
pdfView.maxScaleFactor = 4.0
pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
pdfView.disableBouncing()
//setting swipe gesture
let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(respondLeftSwipeGesture(_:)))
leftSwipeGesture.direction = [UISwipeGestureRecognizer.Direction.left]
pdfView.addGestureRecognizer(leftSwipeGesture)
let rightSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(respondRightSwipeGesture(_:)))
rightSwipeGesture.direction = [UISwipeGestureRecognizer.Direction.right]
pdfView.addGestureRecognizer(rightSwipeGesture)
}
//setting swipe-gesture
@objc func respondLeftSwipeGesture(_ sender: UISwipeGestureRecognizer) {
print("left swipe was detected")
if pdfView.document == nil { return }
scaleOfPdf = pdfView.scaleFactor
pdfView.goToNextPage(self)
pdfView.scaleFactor = scaleOfPdf
}
@objc func respondRightSwipeGesture(_ sender: UISwipeGestureRecognizer) {
print("right swipe was detected")
if pdfView.document == nil { return }
scaleOfPdf = pdfView.scaleFactor
pdfView.goToPreviousPage(self)
pdfView.scaleFactor = scaleOfPdf
}
}
手势识别器作为处理触摸的链或管道工作 - 在一个 (G1) 失败后,第二个 (G2) 尝试识别其手势。这里你至少有 4 个识别器——你的 2 个(left
和 right
),以及 2 个 scrollView 的(pan
和 pinch
)。我将提供仅涵盖 scrollView 的 pan
识别器的简短解决方案,如果您也会看到 pinch
的问题 - 您需要遵循相同的方法。
假设 G1 是您的 left
识别器,G2
是 scrollView 的 pan
识别器。
为了让G2处理和G1一样的触摸,应该让他们同时识别。
此外,用户可能会在垂直滚动时稍微水平移动 his/her 手指,因此在这种情况下,您还希望仅在 G1 放弃滑动且无法识别后才开始滚动。
为了实现这一点,您应该将此代码添加到您的 VC。
override func viewDidLoad(){
super.viewDidLoad()
...
leftSwipeGesture.delegate = self
leftSwipeGesture.cancelsTouchesInView = false
rightSwipeGesture.delegate = self
rightSwipeGesture.cancelsTouchesInView = false
}
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer == leftSwipeGesture
|| gestureRecognizer == rightSwipeGesture
|| otherGestureRecognizer == leftSwipeGesture
|| otherGestureRecognizer == rightSwipeGesture
}
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
guard let _ = gestureRecognizer as? UIPanGestureRecognizer else { return false }
return otherGestureRecognizer == leftSwipeGesture
|| otherGestureRecognizer == rightSwipeGesture
}
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
guard let _ = otherGestureRecognizer as? UIPanGestureRecognizer else { return false }
return gestureRecognizer == leftSwipeGesture
|| gestureRecognizer == rightSwipeGesture
}
如果我添加的 UIGestureRecognizerDelegate
方法没有被调用,您将需要创建一个子类 PDFView
,创建 left/rightSwipeGesture.delegate = pdfView
并在您的 PDFView
子类中覆盖它的 UIGestureRecognizerDelegate
方法具有这种逻辑。
我正在为 iPad 创建一个 PDF 查看器,用户可以使用它通过水平滚动来阅读 PDF。
我创建了以下代码来实现通过手势更改页面的单页视图(同时咨询 How to create a single page vertical scrolling PDFView in Swift 和其他地方)。
尽管这种方法在大多数情况下都可以正常工作,但我发现在放大 PDF 文件时无法检测到(或调用)手势。因此,我无法通过滑动屏幕转到下一页。使用我创建的 extension PDFView {}
函数,我发现禁用 subview
中的用户交互可以让我检测到滑动手势。但是,现在我无法在 PDFView
内滚动页面。如果你能帮我弄清楚如何解决这个问题,我将不胜感激。
我想实现的是类似 PDF Expert
(https://apps.apple.com/us/app/pdf-expert-pdf-reader-editor/id743974925) 的东西,我可以在其中水平滚动到下一页。
非常感谢您的提前帮助!
import UIKit
import PDFKit
//PDF Zoom scale
var scaleOfPdf: CGFloat = 4
extension PDFView {
func disableBouncing(){
for subview in subviews{
if let scrollView = subview as? UIScrollView{
scrollView.bounces = false
return
}
}
class ViewController: UIViewController, UIGestureRecognizerDelegate, UIDocumentPickerDelegate {
@IBOutlet weak var pdfView: PDFView!
override func viewDidLoad(){
super.viewDidLoad()
pdfView.autoresizesSubviews = true
pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleLeftMargin]
pdfView.displayDirection = .horizontal
pdfView.displayMode = .singlePage
pdfView.autoScales = true
// setting a color for background
pdfView.backgroundColor = .black
pdfView.document = pdfDocument
// pdfView.usePageViewController(true, withViewOptions: [UIPageViewController.OptionsKey.interPageSpacing: 20])
pdfView.maxScaleFactor = 4.0
pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
pdfView.disableBouncing()
//setting swipe gesture
let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(respondLeftSwipeGesture(_:)))
leftSwipeGesture.direction = [UISwipeGestureRecognizer.Direction.left]
pdfView.addGestureRecognizer(leftSwipeGesture)
let rightSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(respondRightSwipeGesture(_:)))
rightSwipeGesture.direction = [UISwipeGestureRecognizer.Direction.right]
pdfView.addGestureRecognizer(rightSwipeGesture)
}
//setting swipe-gesture
@objc func respondLeftSwipeGesture(_ sender: UISwipeGestureRecognizer) {
print("left swipe was detected")
if pdfView.document == nil { return }
scaleOfPdf = pdfView.scaleFactor
pdfView.goToNextPage(self)
pdfView.scaleFactor = scaleOfPdf
}
@objc func respondRightSwipeGesture(_ sender: UISwipeGestureRecognizer) {
print("right swipe was detected")
if pdfView.document == nil { return }
scaleOfPdf = pdfView.scaleFactor
pdfView.goToPreviousPage(self)
pdfView.scaleFactor = scaleOfPdf
}
}
手势识别器作为处理触摸的链或管道工作 - 在一个 (G1) 失败后,第二个 (G2) 尝试识别其手势。这里你至少有 4 个识别器——你的 2 个(left
和 right
),以及 2 个 scrollView 的(pan
和 pinch
)。我将提供仅涵盖 scrollView 的 pan
识别器的简短解决方案,如果您也会看到 pinch
的问题 - 您需要遵循相同的方法。
假设 G1 是您的 left
识别器,G2
是 scrollView 的 pan
识别器。
为了让G2处理和G1一样的触摸,应该让他们同时识别。
此外,用户可能会在垂直滚动时稍微水平移动 his/her 手指,因此在这种情况下,您还希望仅在 G1 放弃滑动且无法识别后才开始滚动。
为了实现这一点,您应该将此代码添加到您的 VC。
override func viewDidLoad(){
super.viewDidLoad()
...
leftSwipeGesture.delegate = self
leftSwipeGesture.cancelsTouchesInView = false
rightSwipeGesture.delegate = self
rightSwipeGesture.cancelsTouchesInView = false
}
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer == leftSwipeGesture
|| gestureRecognizer == rightSwipeGesture
|| otherGestureRecognizer == leftSwipeGesture
|| otherGestureRecognizer == rightSwipeGesture
}
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
guard let _ = gestureRecognizer as? UIPanGestureRecognizer else { return false }
return otherGestureRecognizer == leftSwipeGesture
|| otherGestureRecognizer == rightSwipeGesture
}
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
guard let _ = otherGestureRecognizer as? UIPanGestureRecognizer else { return false }
return gestureRecognizer == leftSwipeGesture
|| gestureRecognizer == rightSwipeGesture
}
如果我添加的 UIGestureRecognizerDelegate
方法没有被调用,您将需要创建一个子类 PDFView
,创建 left/rightSwipeGesture.delegate = pdfView
并在您的 PDFView
子类中覆盖它的 UIGestureRecognizerDelegate
方法具有这种逻辑。