6

My code works in iOS 12. But after upgrading to iOS 13, it does not work.

let pinPointRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.pinPoint(sender:)))
pinPointRecognizer.numberOfTapsRequired = 1
self.pdfView.addGestureRecognizer(pinPointRecognizer)

I have tried adding the pinPointRecognizer.numberOfTouchesRequired = 2 and it can trigger pinPoint() function. But I want to trigger pinPoint() in a single tap.

Is this behaviour a bug that will be fixed in the future iOS version? Is there a workaround to fix this?

Thanks!

Updated:

Thank you all for your reply! I am sorry that I may not have the time to test all your answers. I have changed my app's behaviour to work around the problem.

I need to pin a point on PDF file. My workaround is to add an additional layer, which display a pin icon on the center of the PDFView. When a user tap on the PDF view, I will add one pin icon image annotation on the PDFView.

In a word, in my workaround, I still use the tap gesture recognizer. But the recognizer only pin a point on the center of current PDFView. User can zoom in/out and drag around to control where to pin the point.

ysong4
  • 131
  • 1
  • 9

5 Answers5

2
let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(toggleTopBottomView(_:)))
singleTapGesture.numberOfTapsRequired = 1
singleTapGesture.delegate = self
self.pdfContainerView.addGestureRecognizer(singleTapGesture)

@objc func toggleTopBottomView(_ sender: UITapGestureRecognizer){

}


func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}
Matt Long
  • 24,438
  • 4
  • 73
  • 99
1

You can try this with Xcode 11, iOS 13

override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))

    tap.numberOfTapsRequired = 1

    view.addGestureRecognizer(tap)

    view.isUserInteractionEnabled = true

}

@objc func handleTap(_ sender: UITapGestureRecognizer) {
    print("Tapped")
}
Nick
  • 875
  • 6
  • 20
0

the bug seems to be solved on the iOS 13.2 version. Unfortunately I could not find a workaround to solve this issue.

t4nz
  • 59
  • 2
0

Actually i installed the 13.2 Beta with the same issue, however i found a workaround for me. I tested it with 13.1 and it works as well. When i did add a tap gesture recognizer it was working on ios 13 however it would swallow up the taps on Links. Here's what i did to fix the issue: I overrode the addGestureRecognizer on the subclass of PDFView, i then spin through and find the one that is a tap gesture 1 touch (this is provided by apple to handle the links clicking) and create my new tapgesture that i want to show/hide a menu (or your custom actions). I add it to the PDFView and require the built in one by apple to Fail (line 15).

I then allow the shouldRecognizeSimultaneouslyWithGesture which lets both tap gestures to call correclty. if you tap a link, my new one doesn't get called, but if you don't tap a link then it works perfectly and shows/hides my menu. I hope this is useful to someone!

- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{  
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]])
    {
        UITapGestureRecognizer *tapGest = (UITapGestureRecognizer*)gestureRecognizer;
        if (tapGest.numberOfTapsRequired == 1)
        {
            if (![tapGest isEqual:singleTapGesture])
            {
                if (![self.gestureRecognizers containsObject:singleTapGesture])
                {
                    singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
                    [singleTapGesture setNumberOfTapsRequired:1];
                    [singleTapGesture setDelegate:self];
                    [singleTapGesture requireGestureRecognizerToFail:tapGest];
                    [self addGestureRecognizer:singleTapGesture];
                }
            }
        }
    }

    [super addGestureRecognizer:gestureRecognizer];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
  return YES;
}
Jh2170
  • 116
  • 4
0

Unfortunately, I couldn't find a solution which work the same way on both iOS pre and post 13, and the solutions on this post trigger the tap handler when activating a link in the PDF.

Here's the solution I came up with, which is different depending on the iOS version:

/// Since iOS 13, the way to add a properly functioning tap gesture recognizer on a `PDFView`
/// significantly changed. This class handles the setup depending on the current iOS version.
@available(iOS 11.0, *)
final class PDFTapGestureController: NSObject {
    
    private let tapRecognizer: UITapGestureRecognizer
    
    init(pdfView: PDFView, target: Any?, action: Selector?) {
        assert(pdfView.superview != nil, "The PDFView must be in the view hierarchy")
        
        tapRecognizer = UITapGestureRecognizer(target: target, action: action)

        super.init()
        
        if #available(iOS 13.0, *) {
            // If we add the gesture on the superview on iOS 13, then it will be triggered when
            // taping a link.
            // The delegate will be used to make sure that this recognizer has a lower precedence
            // over the default tap recognizer of the `PDFView`, which is used to handle links.
            tapRecognizer.delegate = self
            pdfView.addGestureRecognizer(tapRecognizer)
            
        } else {
            // Before iOS 13, the gesture must be on the superview to prevent conflicts.
            pdfView.superview?.addGestureRecognizer(tapRecognizer)
        }
    }
    
}

@available(iOS 11.0, *)
extension PDFTapGestureController: UIGestureRecognizerDelegate {

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // Make sure we wait for the default PDFView's tap recognizers to fail
        // before triggering our tap handler.
        return (otherGestureRecognizer as? UITapGestureRecognizer)?.numberOfTouchesRequired == tapRecognizer.numberOfTouchesRequired
    }
    
}

Use it like this:

final class PDFViewController: UIViewController {

    // Holds a reference to make sure it is not garbage-collected.
    private var tapGestureController: PDFTapGestureController?

    open override func viewDidLoad() {
        super.viewDidLoad()
        
        let pdfView = PDFView(frame: view.bounds)
        pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(pdfView)
        
        tapGestureController = PDFTapGestureController(pdfView: pdfView, target: self, action: #selector(didTap))
    }

    @objc private func didTap(_ gesture: UITapGestureRecognizer) {
        // Necessary to clear the selection with our custom recognizer for iOS 13.
        if pdfView.currentSelection != nil {
            pdfView.clearSelection()
        } else {
            // Your tap handler...
        }
    }
Mickaël
  • 310
  • 3
  • 8