Swift : UIPanGestureRecognizer delegate method not called - ios

I am facing some weird issue, here is my code for registering pan gesture
public func registerGesture(_ view: UIView) {
self.gesture = UIPanGestureRecognizer(target: self, action: #selector(handleGesture(_:)))
self.gesture?.minimumNumberOfTouches = 1
self.gesture?.maximumNumberOfTouches = 1
self.gesture?.delegate = self
view.addGestureRecognizer(self.gesture!)
}
UIPanGestureRecognizer delegate method is not get called.
extension PanGestureHandler : UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
guard let g = self.gesture else { return false }
guard g.view is UIScrollView else { return false }
return true
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy
otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
}
Instead, if i debug the code and print the line self.gesture.delegate, then the delegate method is getting called.
Every time i need to print the above line to work. Please help me, thanks

For the above issue, i have fixed by adding below sharedinstace,
static let sharedInstance : PanGestureHandler = {
let instance = PanGestureHandler()
return instance
}()
And registering the pangesture for view by,
let gestureInstance = PanGestureHandler.sharedInstance
gestureInstance.registerGesture(self.view)

Related

How to resolve the Gesture conflict with webView and its subview?

I want to add double click gesture to my webview, but not intercept its own click callback,I a subview to response double click gesture , but click callback of the webview will be invalid
{
webMaskView = UIView()
webVie w.addSubview(webMaskView)
webMaskView.snp.makeConstraints { (make) in
make.left.right.top.bottom.equalTo(webV)
}
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(webViewTwoTaped(_ :)))
doubleTap.delegate = self
doubleTap.numberOfTapsRequired = 2
webMaskView.addGestureRecognizer(doubleTap)
webMaskView.isUserInteractionEnabled = true
webMaskView.backgroundColor = UIColor.blue.withAlphaComponent(0.1)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return true
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
You no need to add subview for double tap gesture, You can add double tap gesture directly on Webview or WKWebView.

UIGestureRecognizer recognize order problem

I have a red view and a green view (green view is a subview of redview),and I add a gestureRecognizer to each of them.
And both grestureRecognizer's shouldRecognizeSimultaneouslyWith return YES.
But when I tap the green view , the redview's gesture delegate method shouldRecognizeSimultaneouslyWith is called first .
Because i think the hit-test view should be the green view . so the green view 's shouldRecognizeSimultaneouslyWith should be the first .
How do the iOS to decide which grestureRecognizer should be recogonized first ?
Post the code and print logs:
class GreenView: UIView,UIGestureRecognizerDelegate{
override func awakeFromNib() {
let gesture = UITapGestureRecognizer(target: self, action: #selector(greenTap))
gesture.delegate = self
self.addGestureRecognizer(gesture)
}
#objc func greenTap(){
print("greenTap")
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
print("greenTap shouldRecognizeSimultaneouslyWith")
return true
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
print("green gestureRecognizerShouldBegin")
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
}
class RedView: UIView,UIGestureRecognizerDelegate{
override func awakeFromNib() {
let gesture = UITapGestureRecognizer(target: self, action: #selector(redTap))
gesture.delegate = self
self.addGestureRecognizer(gesture)
}
#objc func redTap(){
print("redTap")
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
print("redTap gestureRecognizerShouldBegin")
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
print("redTap shouldRecognizeSimultaneouslyWith")
return true
}
}
and the prints are :
green gestureRecognizerShouldBegin
redTap gestureRecognizerShouldBegin
green gestureRecognizerShouldBegin
redTap shouldRecognizeSimultaneouslyWith
greenTap shouldRecognizeSimultaneouslyWith
redTap
greenTap
and we can see that the redview(superview) 's shouldRecognizeSimultaneouslyWith and action method is called before the greenview(subview)'s methods
Don't add the green view as subview of red view. Just add the green view outside red view above it and center the constraints to red view

How to disable UIScrollView to a pan gesture recognizer?

How do I disable, or force to fail, the gesture recognizer in a UIScrollView when a pan gesture recognizer, lets call it SomePanGestureRecognizer, is called?
The gestureRecognizer(_:shouldBeRequiredToFailBy:) method takes a gesture recognizer parameter, not a pan gesture recognizer and I don't know if that's why I can't get it to work or because I'm making a syntax error.
I have UIScrollView subclassed and the method used to force fail is in the delegate below:
class CustomScrollView: UIScrollView {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
private func configure() {
isScrollEnabled = true
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
isPagingEnabled = true
bounces = false
alwaysBounceVertical = false
alwaysBounceHorizontal = false
}
}
// gesture recognizer delegate
extension CustomScrollView: UIGestureRecognizerDelegate {
// allow simultaneous gestures
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
// force failure
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// TLDR: disable uiscrollview when SomePanGestureRecognizer is called
}
}
And here is the pan gesture recognizer that needs to force the gesture recognizer in the UIScrollView to fail:
func addSomePanGestureRecognizer() {
SomePanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(oneBPanGestureHandler(gesture:)))
oneBHandle.addGestureRecognizer(SomePanGestureRecognizer)
}
UPDATE I subclassed the UIPanGestureRecognizer and got it to work using the simultaneous delegate but I fear that this is a shaky way to do it because I'm relying on UIKit to always disable the UIScrollView before the custom pan gesture.
// gesture recognizer delegate
extension CustomScrollView: UIGestureRecognizerDelegate {
// simultaneous gestures
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if otherGestureRecognizer is CustomPanGestureRecognizer {
return false
} else {
return true
}
}
}
UPDATE 2 This also works but I don't know why because I feel like it shouldn't. Shouldn't it be the other way around?
// force failure
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if otherGestureRecognizer is CustomPanGestureRecognizer {
return true
} else {
return false
}
}
I believe this is what you're looking for:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let isPanAndOtherRecognizer = gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is SomePanGestureRecognizer
return !isPanAndOtherRecognizer
}
// force failure
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let isPanAndOtherRecognizer = gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is SomePanGestureRecognizer
return isPanAndOtherRecognizer
}

tap gesture is not working when i touch my player( MPMovieplayerController)

here i try to merge all video and display that video in screen. but i need to add tap gesture when i press the player screen it should handle some action. but if i tab on view its working but if i tap on player its not working. any solution please
EDITED:
class ViewController: UIViewController,UIGestureRecognizerDelegate {
var location: CGPoint!
var gestureRecognizer: UITapGestureRecognizer!
var videoPlayer = MPMoviePlayerController()
override func viewDidLoad() {
super.viewDidLoad()
musicImg.hidden = true
let gestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTapGesture")
gestureRecognizer.delegate = self;
videoPlayer.view.addGestureRecognizer(gestureRecognizer)
}
func handleTap(gestureRecognizer: UIGestureRecognizer) {
//location = gestureRecognizer .locationInView(videoPlayer.view)
print("tapped")
}
//#pragma mark - gesture delegate
// this allows you to dispatch touches
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
Displaying my selected video in screen:
self.mediaUI.dismissViewControllerAnimated(true, completion: nil)
self.videoPlayer = MPMoviePlayerController()
self.videoPlayer.contentURL = self.videoURL
self.videoPlayer.controlStyle = .Embedded
self.videoPlayer.scalingMode = .AspectFill
self.videoPlayer.shouldAutoplay = true
self.videoPlayer.backgroundView.backgroundColor = UIColor.clearColor()
self.videoPlayer.fullscreen = true
self.videoPlayer.view.frame = CGRectMake(38, 442, 220, 106)
self.view.addSubview(self.videoPlayer.view)
self.videoPlayer.play()
self.videoPlayer.prepareToPlay()
My screen in fully white, no button,label are showing
Try with this...
let gestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTapGesture")
gestureRecognizer.delegate = self;
If you want to add gesture in movie player controller
videoPlayer.view.addGestureRecognizer(gestureRecognizer)
and if you want for main screen...
self.view.addGestureRecognizer(gestureRecognizer)
And implement delegate methods
#pragma mark - gesture delegate
// this allows you to dispatch touches
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
return true
}
// this enables you to handle multiple recognizers on single view
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer touch: UITouch) -> Bool {
return true
}

Detect UIScreenEdgeGestureRecognizer and fail UIPanGestureRecognizer

In my ViewController I have a UIScreenEdgeGestureRecognizer for switching views but also a UITableView with a custom UITableViewCell. In this custom UITableViewCell is a UIPanGestureRecognizer for swiping the cells.
I added gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so both of the gestures are working and gestureRecognizerShouldBegin to prevent the conflict of vertical scrolling.
The question is, how can I give the UIScreenEdgeGestureRecognizer priority? When I swipe at the edge of the screen, I want to switch the views without panning the cells. I figured I should be using the delegate methods, but so far the more I read the more confused I'm getting.
Code in custom UITableViewCell:
override func viewDidload() {
var recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
recognizer.delegate = self
addGestureRecognizer(recognizer)
}
override func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGesture = gestureRecognizer as? UIPanGestureRecognizer {
let velocity = panGesture.velocityInView(superview!)
if fabs(velocity.x) > fabs(velocity.y) { return true }
return false
}
return false
}
ViewController:
override func viewDidLoad() {
let rightScreenEdgeRecognizer = EdgePanGesture(target: self, action: "changeView:")
rightScreenEdgeRecognizer.edges = .Right
view.addGestureRecognizer(rightScreenEdgeRecognizer)
}
I also tried identifying the recognizers with:
gestureRecognizer.isKindOfClass(UIScreenEdgePanGestureRecognizer)
and
gestureRecognizer as? UIScreenEdgePanGestureRecognizer
But all were failed.
Turns out I was looking at the right direction with gestureRecognizer as? UIScreenEdgePanGestureRecognizer but instead of gestureRecognizer I should have used otherGestureRecognizer.
override func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if let recognizer = otherGestureRecognizer as? UIScreenEdgePanGestureRecognizer {
return true
}
return false
}

Resources