【问题标题】:How to resolve the conflict of gestures between PDFView and SCrollView [Swift5, iOS 14]如何解决 PDF View 和 SCrollView 之间的手势冲突 [Swift 5, iOS 14]
【发布时间】:2021-01-12 06:29:30
【问题描述】:

我正在为 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
    }
}

【问题讨论】:

    标签: ios swift uiscrollview uigesturerecognizer pdfview


    【解决方案1】:

    手势识别器作为处理触摸的链或管道工作 - 在第一个 (G1) 失败后,第二个 (G2) 尝试识别其手势。在这里,您至少有 4 个识别器 - 您的 2 个(leftright)和 2 个 scrollView 的(panpinch)。我将给出仅涵盖 scrollView 的 pan 识别器的简短解决方案,如果您也看到 pinch 的问题 - 您需要遵循相同的方法。

    假设 G1 是您的 left 识别器,G2 是 scrollView 的 pan 识别器。 为了使 G2 处理与 G1 相同的触摸,应告知它们同时识别。

    此外,用户可能会在垂直滚动时稍微水平移动他/她的手指,因此在这种情况下,您还希望仅在 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 方法。

    【讨论】:

    • 非常感谢您回答我的问题,@EugeneDudnyk!我很抱歉;看来我完全错过了你的答案。我今天尝试了你的代码!它正在工作!!!(我处理了几个错误:第一个错误是说不要将optional 用于func gestureRecognizer(...。当我删除optionals 时,Cannot find 'leftSwipeGesture' in scope 出现了。因此,我移动了override func viewDidLoad(){ 内的块。现在它正在检测所有手势!!!非常感谢!!!
    • 我认为现在是将我的答案标记为已接受的最佳时机:)
    • 太真实了!!对不起,我忘了这样做。再次感谢你,我希望你有一个美好的一天。 ^^
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多