Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIControl endTrackingWithTouch not called

Tags:

ios

uicontrol

I have a view with a tap gesture recognizer. A subview of this view is an instance of my custom class, which inherits from UIControl. I am having an issue where the UIControl subclass will sometimes allow touch events to pass through to the parent view when it shouldn't.

Within the UIControl subclass, I have overridden these functions (code is in Swift)

override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    return true
}

override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    // The code here moves this UIControl so its center is at the touchpoint
    return true
}

override func endTrackingWithTouch(touch: UITouch,withEvent event: UIEvent)
{
    // Something important happens here!
}

This system works just fine if the user touches down within the UIControl, drags the control around in both X and Y directions, and then lifts off the screen. In this case, all three of these functions are called, and the "something important" happens.

However, if the user touches down with the UIControl, drags the control around only in the X direction, and then lifts off the screen, we have a problem. The first two functions are called, but when the touchpoint lifts off the screen, the tap gesture recognizer is called, and endTrackingWithTouch is not called.

How do I make sure that endTrackingWithTouch is always called?

like image 208
user1021430 Avatar asked Sep 19 '14 17:09

user1021430


Video Answer


2 Answers

I fixed this in a way that I consider to be a hack, but there's really no alternative, given how UIGestureRecognizer works.

What was happening was that the tap gesture recognizer was canceling the control's tracking and registering a tap gesture. This was because when I was dragging horizontally, I just happened to be dragging short distances, which gets interpreted as a tap gesture.

The tap gesture recognizer must be disabled while the UIControl is tracking:

override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    pointerToSuperview.pauseGestureRecognizer()
    return true
}

override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
{
    // The code here moves this UIControl so its center is at the touchpoint
    return true
}

override func endTrackingWithTouch(touch: UITouch,withEvent event: UIEvent)
{
    // Something important happens here!
    pointerToSuperview.resumeGestureRecognizer()
}

override func cancelTrackingWithEvent(event: UIEvent?)
{
    pointerToSuperview.resumeGestureRecognizer()
}

In the superview's class:

pauseGestureRecognizer()
{
    tapGestureRecognizer.enabled = false
}

resumeGestureRecognizer()
{
    tapGestureRecognizer.enabled = true
}

This works because I'm not dealing with multitouch (it's OK for me not to receive tap touch events while tracking touches with the UIControl).

Ideally, the control shouldn't have to tell the view to pause the gesture recognizer - the gesture recognizer shouldn't be meddling with the control's touches to begin with! However, even setting the gesture recognizer's cancelsTouchesInView to false cannot prevent this.

like image 136
user1021430 Avatar answered Oct 12 '22 16:10

user1021430


There's a way to fix this that's nicely self-contained: instantiate your own TapGestureRecognizer and attach it to your custom control, e.g. in Objective-C,

_tapTest = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
_tapTest.numberOfTapsRequired = 1;
[self addGestureRecognizer:_tapTest];

and then implement the tapped action handler to process the tap:

- (void)tapped:(UITapGestureRecognizer *)recognizer {...}

In my case, I handle tapped the same as endTrackingWithTouch:withEvent:; your mileage may vary.

This way, you get the tap before any superview can snatch it, and you don't have to worry about the view hierarchy behind your control.

like image 22
Adam Wilt Avatar answered Oct 12 '22 15:10

Adam Wilt