Search code examples
coronasdktap

Corona: Double tap / single tap


I'm attempting to detect both single and double taps in Corona SDK. I have utilised:

system.setTapDelay(0.5)

...in my main.lua file which I understood would ensure a single tap event was not passed unless a further tap event had not been received in 0.5 seconds. According to the docs the delay is specified in seconds not milliseconds hence the 0.5.

I have then utilised this:

function mapGroup:tap(event)
    if event.numTaps >= 2 then
        print "double tap"
    else
        print "single tap"
    end
    return true
end

This, as expected returns single and double tap. However it is firing twice for double taps:

single tap
double tap

How can I prevent Corona firing the single tap until we know it is not going to be a double tap?


Solution

  • It's more tricky than it seems at first.

    I think system.setTapDelay() does work. At least it seems to. But my understanding is that is not meant to exclude single taps. Only to accept slower double taps. Or maybe the documentation of this function is just misleading. In any case let's hope the Corona dev team clarifies that in the future.

    Now in your app you have objects that must react to single taps, and objects that must react to double taps, correct?

    And maybe even objects that must react to one, or the other, but not to both. But you have to be aware that with this third design choice, in case of a single tap your object will have to "wait" until it is sure it wasn't the first hit of a double tap. You follow? In other words, to distinguish single and double taps on the same object might result in single taps that "lag" a bit.

    To implement all of this in a simple way I would go like this:

    function onSingleTap( event )
        if event.numTaps == 1 then
            print("received a single tap")
        end
    end
    
    objectThatRespondsToSingleTapOnly:addEventListener( "tap", onSingleTap )
    
    function onDoubleTap( event )
        if event.numTaps >= 2 then
            print("received a double tap")
        end
    end
    
    objectThatRespondsToDoubleTapOnly:addEventListener( "tap", onDoubleTap )
    

    Now if you also want objects that distinguish the single from the double you could add this:

    local doubleTapTimeout = 600 -- values under 300 become hard to use
    -- BTW make this a little higher than the tap delay, if you set it manually
    
    function onExclusiveSingleTap( event )
        print("received an exclusive single tap")
    end
    
    function onExclusiveDoubleTap( event )
        print("received an exclusive double tap")
    end
    
    function onExclusiveTap( event )
        if event.numTaps == 1 then
            event.target.singleTapWaiting = timer.performWithDelay(
                doubleTapTimeout,
                function(e) onExclusiveSingleTap( event ) end
            )
        elseif event.numTaps >= 2 then
            timer.cancel( event.target.singleTapWaiting )
            onExclusiveDoubleTap( event )
        end
    end
    
    objectThatRespondsToBothTaps:addEventListener( "tap", onExclusiveTap )
    

    I only wonder if you shouldn't copy the values of the event object in the Lua closure instead of passing its reference, which might result in some memory leaks.

    function(e) onExclusiveSingleTap( {
        name = "tap",
        x = event.x,
        y = event.y,
        numTaps = 1,
        target = event.target
    } ) end