This guide explains the difference between tap, touch, and multitouch and how to handle the events associated with each method.
If you're new to Corona and haven't yet explored basic screen interactivity and events, please begin by reading the Basic Interactivity and Event Detection guide.
Tap events are the most basic form of screen interactivity. Essentially, a tap is represented by the user touching the screen and lifting off at the same approximate point. The tap event is considered successful only if the user touches and releases at that point.
In Corona, you can listen for tap events by registering a "tap"
event listener on most common display objects:
local function tapListener( event ) -- Code executed when the button is tapped print( "Object tapped: " .. tostring(event.target) ) -- "event.target" is the tapped object return true end local myButton = display.newRect( 100, 100, 200, 50 ) myButton:addEventListener( "tap", tapListener ) -- Add a "tap" listener to the object
The event
properties returned from a tap include:
event.target
— reference to the object that was tapped.
event.name
— string value of "tap"
.
event.numTaps
— the number of taps on the screen. The default delay between what is considered the next tap in sequence is 0
, but this time can be adjusted with the system.setTapDelay() function.
event.x
/ event.y
— the x and y position of the tap, in content coordinates.
Unlike touch events, the tap event does not include a phase
property — the tap is a singular action involving both a touch and release, so you don't need to handle the phase in any special manner.
Using the event.numTaps
property, you can easily determine whether an object was tapped multiple times and concurrently ignore single taps on the object. To achieve this, just ensure that event.numTaps
is equal to 2
or higher and ignore return true
local function tapListener( event ) if ( event.numTaps == 2 ) then print( "Object double-tapped: " .. tostring(event.target) ) elseif ( event.numTaps == 3 ) then print( "Object triple-tapped: " .. tostring(event.target) ) else return true end end local myButton = display.newRect( 100, 100, 200, 50 ) myButton:addEventListener( "tap", tapListener )
Touch events provide for a much greater level of screen interactivity. Using touch events, you can detect when the user first touches the screen and when the touch is lifted off the screen. You can also track the motion of the touch as it moves around the screen. To accomplish this, Corona offers the event.phase
property in one of four states:
"began"
— indicates that a touch has started on the screen."moved"
— indicates that a touch has moved on the screen."ended"
— indicates that a touch has been lifted from the screen."cancelled"
— indicates that the system cancelled tracking of the touch (not to be confused with "ended"
).You can listen for touch events by registering a "touch"
event listener on most common display objects:
local function myTouchListener( event ) if ( event.phase == "began" ) then -- Code executed when the button is touched print( "object touched = " .. tostring(event.target) ) -- "event.target" is the touched object elseif ( event.phase == "moved" ) then -- Code executed when the touch is moved over the object print( "touch location in content coordinates = " .. event.x .. "," .. event.y ) elseif ( event.phase == "ended" ) then -- Code executed when the touch lifts off the object print( "touch ended on object " .. tostring(event.target) ) end return true -- Prevents tap/touch propagation to underlying objects end local myButton = display.newRect( 100, 100, 200, 50 ) myButton:addEventListener( "touch", myTouchListener ) -- Add a "touch" listener to the object
The event properties returned from a touch include:
event.id
— a unique identifier that distinguishes between multiple touches across different touch events. See Multitouch below for more details.
event.target
— reference to the object that was touched.
event.name
— string value of "touch"
.
event.phase
— the phase of the touch as described above.
event.pressure
— number indicating the pressure of a touch, typically used to detect "3D Touch" events on compatible iOS devices. See the documentation for more information.
event.time
— the time in milliseconds since the start of the application, accessible from within the touch listener function.
event.x
/ event.y
— the x and y position of the touch, in content coordinates.
event.xStart
/ event.yStart
— the x and y position of the touch from the "began"
phase of the touch sequence, in content coordinates.
Enabling multitouch in an app lets you detect and handle multiple user touches on the screen at the same time.
Because multitouch is disabled by default, you must first enable it via the system.activate() function:
system.activate( "multitouch" )
Multitouch functionality is only supported on actual mobile devices
With multitouch enabled, listen for touch events by registering a "touch"
event listener on the object(s), exactly as described in Touch Detection above. Then, compare the event.id
property to determine which specific touch event sequence is being returned. For example:
-- Activate multitouch system.activate( "multitouch" ) -- Create a display object on the screen local newRect1 = display.newRect( display.contentCenterX, display.contentCenterY, 280, 440 ) newRect1:setFillColor( 1, 0, 0.3 ) -- Touch event listener local function touchListener( event ) print( "Phase: " .. event.phase ) print( "Location: " .. tostring(event.x) .. "," .. tostring(event.y) ) print( "Unique touch ID: " .. tostring(event.id) ) print( "----------" ) return true end -- Add a touch listener to the object newRect1:addEventListener( "touch", touchListener )
When the user touches the screen, the event is dispatched to the display hierarchy. Only those display objects that intersect the touch location on the screen will receive the event.
Tap and touch events propagate through these objects in a particular order. By default, the first object to receive the event is the
Tap and touch events propagate until they are "handled." This means that if you have multiple objects overlaying each other in the display hierarchy, and a tap or touch event listener has been applied to each, the event will propagate through all of these objects. However, you can stop propagation to the next underlying object by telling Corona that the event has been handled. This is as simple as returning true
from the event listener — this stops the propagation cycle and prevents any underlying objects from responding to the hit event.
local function myTouchListener( event ) if ( event.phase == "began" ) then -- Code executed when the button is touched print( "object touched = " .. tostring(event.target) ) -- "event.target" is the touched object end return true -- Prevents tap/touch propagation to underlying objects end local myButton = display.newRect( 100, 100, 200, 50 ) myButton:addEventListener( "touch", myTouchListener )
If the tap or touch event is still not handled after traversal through the entire display hierarchy, it is broadcast as a global event to the Runtime listener.
You can direct all touch events to a specific display object by setting focus on the object. This instructs the system to deliver all future touch events to that object, effectively making it "own" the first touch it receives for the lifetime of that touch.
Consider a typical button — if the user touches the button and, without lifting/releasing touch, slides outside the button bounds, the button probably should not trigger an action upon touch release. Similary, if the touch slides off the button and intersects another
To set focus on a display object, pass its object reference to StageObject:setFocus(). This may be event.target
within a touch listener, or it can be any direct reference to the object itself.
In contrast, when you wish to release focus on the object, simply pass nil
to StageObject:setFocus():
display.getCurrentStage():setFocus( nil )
This example shows how you might handle focus and release of multiple objects:
-- Create two display objects on the screen local newRect1 = display.newRect( display.contentCenterX, 160, 60, 60 ) newRect1:setFillColor( 1, 0, 0.3 ) local newRect2 = display.newRect( display.contentCenterX, 320, 60, 60 ) newRect2:setFillColor( 0.3, 0, 1 ) -- Touch event listener local function touchListener( event ) if ( event.phase == "began" ) then event.target.alpha = 0.5 -- Set focus on object display.getCurrentStage():setFocus( event.target ) elseif ( event.phase == "ended" or event.phase == "cancelled" ) then event.target.alpha = 1 -- Release focus on object display.getCurrentStage():setFocus( nil ) end return true end -- Add a touch listener to each object newRect1:addEventListener( "touch", touchListener ) newRect2:addEventListener( "touch", touchListener )
Touch focus can also be achieved when multitouch is enabled via system.activate(). However, because there may be multiple touches on the same object, you must dedicate the first touch it receives by a unique internal identifier. This is done by passing the event.id
property gathered from the touch listener as the second argument to StageObject:setFocus():
display.getCurrentStage():setFocus( event.target, event.id )
Then, when you wish to release focus on the object, simply pass nil
as the second argument to StageObject:setFocus():
display.getCurrentStage():setFocus( event.target, nil )
This example shows how you might handle focus and release of multiple objects while multitouch is enabled:
-- Activate multitouch system.activate( "multitouch" ) -- Create two display objects on the screen local newRect1 = display.newRect( display.contentCenterX, 160, 60, 60 ) newRect1:setFillColor( 1, 0, 0.3 ) local newRect2 = display.newRect( display.contentCenterX, 320, 60, 60 ) newRect2:setFillColor( 0.3, 0, 1 ) -- Touch event listener local function touchListener( event ) print( "Unique touch ID: " .. tostring(event.id) ) if ( event.phase == "began" ) then event.target.alpha = 0.5 -- Set focus on object using unique touch ID display.getCurrentStage():setFocus( event.target, event.id ) elseif ( event.phase == "ended" or event.phase == "cancelled" ) then event.target.alpha = 1 -- Release focus on object display.getCurrentStage():setFocus( event.target, nil ) end return true end -- Add a touch listener to each object newRect1:addEventListener( "touch", touchListener ) newRect2:addEventListener( "touch", touchListener )