Detect a finger after TouchDown leaving the control, before TouchUp

1.8k Views Asked by At

I have some UIButton instances that execute different code on their UIControlEventTouchDown and UIControlEventTouchUpInside events. At the moment I'm hitting an issue where if the user touched down, then dragged their finger out of the UIButton's bounds before touching up, the TouchUpInside code isn't run, and as such, the next TouchDown causes a crash.

I need a way to error-proof this, so that after a TouchDown, the TouchUpInside code is executed if the finger is: a) lifted over the button, b) dragged off the button, or c) cancelled in some other way.

a) is solved by UIControlEventTouchUpInside, and I've tried both UIControlEventTouchDragExit and UIControlEventTouchUpOutside, but I can't get situations b) or c) solved.

Any idea how I can handle this? Here's my code:

[newBall.button addTarget: self action: @selector(buttonDown:) forControlEvents: UIControlEventTouchDown];
[newBall.button addTarget: self action: @selector(buttonUp:) forControlEvents: UIControlEventTouchUpInside];

- (void) buttonDown: (id) sender
{
    NSLog(@"Finger down on button %d!", [sender tag]);

    int senderTag = [sender tag];

    for (CBBall *i in balls) {
        int currentTag = [i.button tag];
        if (currentTag == senderTag) {
            i.body -> f = cpvzero;
            [i replaceDynamicBall: i withStaticOneAtLocation: cpBodyGetPos(i.body)];
            [i setIsBeingTouched: YES];
        }
    }
}

- (void) buttonUp: (id) sender
{
    NSLog(@"Finger up on button %d!", [sender tag]);

    int senderTag = [sender tag];

    for (CBBall *i in balls) {
        int currentTag = [i.button tag];
        if (currentTag == senderTag) {
            [i replaceStaticBall: i withDynamicOneAtLocation: cpBodyGetPos(i.body)];
            [i setIsBeingTouched: NO];
        }
    }
}
4

There are 4 best solutions below

6
On BEST ANSWER

Set the target for UIControlEventAllTouchEvents and then in the targeted method check the value of isTracking property of UIbutton This will solve your problem.

EDIT:

if([btn isTracking])
{
    if(flag)
    {
       flag=NO;
       //Your TouchDown Code
    }
}
else
{
   flag=YES;
   //your Touch Cancel and Exit code
}

and set flag to YES Before

1
On

Set the same target to all events you need.

[btn addTarget:self action:@selector(yourMethodtoHandleTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
[btn addTarget:self action:@selector(yourMethodtoHandleTouchUpInside:) forControlEvents:UIControlEventTouchDragOutside];
[btn addTarget:self action:@selector(yourMethodtoHandleTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
2
On

For cancel touch you can use UIControlEventTouchCancel .

and for b) , i think UIControlEventTouchDragExit should work , i have tried it and its working , make sure you have properly connected the IBAction.

0
On

Answering your points

b) dragged off the button, you need to use UIControlEventTouchDragOutside

c) cancelled in some other way, you need ot use UIControlEventTouchCancel

As such:

[newBall.button addTarget:self action:@selector(someMethod:withEvent: )
              forControlEvents: UIControlEventTouchCancel | UIControlEventTouchDragOutside];