Search code examples
iosobjective-cxcodetouchesmoved

Only allowing a single touchesMoved method triggered per period of time?


I am using touchesMoved with a coordinate system to detect and respond to user touches within certain areas of the screen. For example, if I have a virtual keyboard and the user swipes across the keys, it reads the coordinates and responds:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch * touch = [[event allTouches] anyObject];
    CGPoint point = [touch locationInView:touch.view];
    if(point.y < 333 && point.y > 166 && point.x < 90 && point.x > 20)
    {
       //do something
    }
}

...However, the problem is, if the user slowly drags across the keys, or the border between keys, the method is triggered several times in a row, playing the piano key sound in a stutter.

How can I prevent this stutter? I think setting a minimum delay of 0.25 seconds between each successive if statement triggering would help. Also, this delay would only be for a specific if statement -- I want the user to be able to drag across the keys quickly and trigger different key's if-statement as quick as they want.

Does anyone know how to code something like this?


Solution

  • Try this:

    BOOL _justPressed; // Declare this in your @interface
    
    ...
    
    - (void)unsetJustPressed {
        _justPressed = NO;
    }
    

    Then, in your touchesMoved:

    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        if (_justPressed) {
            // A key was just pressed, so do nothing.
            return;
        }
        else {
            _justPressed = YES;
    
            // Do stuff here
    
            [self performSelector:@selector(unsetJustPressed)
                       withObject:nil
                       afterDelay:0.25];
        }
    }
    

    This way, you set a variable _justPressed to YES every touchesMoved:withEvent: is called (or within a specific conditional in there, depending on what you want to do), and you use performSelector:withObject:afterDelay: to set _justPressed to NO after a certain time period, and so you can just check whether _justPressed is YES when touchesMoved: is called to ascertain whether it was called recently.

    Remember, you don't have to return from the method like in the example above, you can simply use _justPressed to check whether you should play the sound, but still perform your other actions. The example is just to give you a basic idea of what to do.