Events and Listeners
Events are dispatched to listeners. Event listeners can be either functions or objects (see Function vs Table Listeners below). In both cases, when an event occurs, the listener will be invoked and be supplied with a table representing the event. All events will have a property name that identifies the kind of event.
Registering for Events
Certain objects you create using Corona's libraries are event listeners. This includes both display objects and the global Runtime object. You can add and remove listeners for events using the following object methods:
In the example below, an image display object registers to receive Touch Events. Touch events are not broadcast globally. Only objects that register for the event and lie underneath it will be candidates for receiving the touch. See Touch Events for more information.
| Function Listeners | Table Listeners |
|---|---|
local button = display.newImage("button.png") local function listener(event) print(event.name.."occurred") return true end button:addEventListener( "touch", listener ) |
local button = display.newImage("button.png") function button:touch(event) print(event.name.."occurred") return true end button:addEventListener( "touch", button ) |
In contrast, Runtime Events are dispatched by the system. They are broadcast to all listeners. Below is an example of registering for an enterFrame event:
| Function Listeners | Table Listeners |
|---|---|
local function listener(event) print(event.name.."occurred") end Runtime:addEventListener( "enterFrame", listener ) |
local listener = {} function listener:enterFrame(event) print(event.name.."occurred") end Runtime:addEventListener( "enterFrame", listener ) |
Function vs Table Listeners
Listeners can be either functions or table/display objects.
When a function listener is invoked, it is passed a table representing the event:
1 2 3 4 5 | local myListener = function( event ) print( "Listener called with event of type " .. event.name ) end Runtime:addEventListener( "touch", myListener ) Runtime:addEventListener( "enterFrame", myListener ) |
Sometimes a function listener is not convenient because certain variables are not in scope when the listener is triggered (invoked). In these situations, object listeners should be used. Object listeners must have an instance method with a name corresponding to the event name:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -- assume MyClass and MyClass:new() already exist function MyClass:enterFrame( event ) print( "enterFrame called at time: " .. event.time ) end function MyClass:touch( event ) print( "touch occurred at ("..event.x..","..event.y..")" ) end local myObject = MyClass:new() Runtime:addEventListener( "touch", myObject ) Runtime:addEventListener( "enterFrame", myObject ) |
Runtime Events
Since they have no specific target, Runtime Events are only sent to the global Runtime. Instead, they are broadcast to all registered listeners. The events all have string names:
enterFrame
enterFrame events occur at the frame interval of the application. They are only sent to the global Runtime object.
The following properties are available in this event:
- event.name is the string
"enterFrame". - event.time is the time in milliseconds since the start of the application.
system
System events are dispatched to notify the application of external events such as when the device needs to suspend the application because of an incoming phone call. These events are only sent to the global Runtime object.
The following properties are available in this event:
- event.name is the string
"system". - event.type is a string identifying the type of event. The string values could be:
"applicationStart"occurs when the application is launched and all code in main.lua is executed."applicationExit"occurs when the user quits the application."applicationSuspend"occurs when the device needs to suspend the application such as during a phone call or if the phone goes to sleep from inactivity. In the simulator, this corresponds to the simulator running in the background. During suspension, no events (not evenenterFrameevents) are sent to the application while suspended, so if you have code that depends on time, you should account for the time lost to an application being suspended."applicationResume"occurs when the application resumes after a suspend. On the phone, this occurs if the application was suspended because of a phone call. On the simulator, this occurs when the simulator was in the background and now is the foreground application.
orientation
Orientation events occur when the device orientation changes. They only occur on devices with accelerometer support. They are only sent to the global Runtime object.
The following properties are available in this event:
- event.name is the string
"orientation". - event.type is a string identifying the orientation:
"portrait""landscapeLeft""portraitUpsideDown""landscapeRight""faceUp""faceDown"
- event.delta is the angular difference between the ending and starting orientation. 0 if the two orientations lie in different planes.
accelerometer
Accelerometer events let you detect sudden movements and determine the device's orientation relative to gravity. These events are only dispatched on devices that have support accelerometer. They are only sent to the global Runtime object.
The following properties are available in this event:
- event.name is the string
"accelerometer". - event.xGravity is the acceleration due to gravity in the x-direction
- event.yGravity is the acceleration due to gravity in the y-direction
- event.zGravity is the acceleration due to gravity in the z-direction
- event.xInstant is the instantaneous acceleration in the x-direction
- event.yInstant is the instantaneous acceleration in the y-direction
- event.zInstant is the instantaneous acceleration in the z-direction
- event.isShake is true when the user shakes the device
location (GPS)
These are location events generated by the GPS hardware. They are only sent to the global Runtime object.
- event.name is the string
"location". - event.latitude is the latitude in degrees.
- event.longitude is the longitude in degrees.
- event.altitude is the altitude in meters.
- event.accuracy is the accuracy of the location in meters. If negative, then the latitude and longitude are not valid.
- event.speed is the instantaneous speed of the device in meters per second.
- event.direction is the direction the device is travelling in degrees clockwise from true North. If negative, the direction is invalid.
- event.time is the UTC timestamp of the location event.
When an error occurs, the following properties will be non-nil:
- event.errorMessage is a string with an error description. This property only exists when an error occurs. It may be localized so it may vary depending on the user's language setting.
- event.errorCode is a platform-specific integer for the error which is not language dependent. This property only exists when an error occurs.
heading (compass)
These are heading events generated by the compass hardware, if available on the device. Note: the Android OS only supports event.magnetic, not event.geographic (see below). These events are only sent to the global Runtime object.
The following properties are available in this event:
- event.name is the string
"heading". - event.geographic represents a heading in degrees (clockwise) relative to the geographic North Pole, sometimes known as true North.
- event.magnetic represents a heading in degrees (clockwise) relative to the magnetic North Pole.
memoryWarning (iOS)
The iOS low memory warning is exposed as a Corona event type named "memoryWarning", sent to the global Runtime object. This event has no fields.
When this event fires, the OS reserves the right to forcibly shut down the application in about five seconds (although it may or may not do so). Apple advises developers to listen for this warning, and to handle it by freeing as much memory as possible when it is received.
Here is an example of a listener for this event:
1 2 3 4 5 | local function handleLowMemory( event ) print( "memory warning received!" ) end Runtime:addEventListener( "memoryWarning", handleLowMemory ) |
Note that Android has no equivalent of this event, so currently this is an iOS-only feature of Corona.
Targeted Events
Targeted events are not broadcast. They are sent to a single target (a function or table listener).
completion
Completion events signal the end of an interaction. Typically these are dispatched at the end of a modal interaction such as using the camera or throwing up a native alert.
The following are common properties of this event:
- event.name is the string
"completion".
Additional properties are given depending on the modal interaction (see media.playVideo, media.show, and native.showAlert).
timer
Timer events are used in conjunction with the timer library.
The following properties are available in this event:
- event.name is the string
"timer". - event.source corresponds to the timer registered to send the event.
- event.count is the number of times that the timer has fired the listener. This is useful if you registered the timer to fire multiple times.
- event.time is the time in milliseconds since the start of the application.
urlRequest
URL request events are dispatched to the listener registered with the native.webPopup() function. They are sent when the web popup is about to request a url and also when a url fails to load.
The following properties are available in this event:
- event.name is the string
"urlRequest". - event.url is the absolute URL of the request.
- event.errorMessage is a string with an error description. This property only exists when an error occurs. It may be localized so it may vary depending on the user's language setting.
- event.errorCode is a platform-specific integer for the error which is not language dependent. This property only exists when an error occurs.
Touch Events
For a tutorial on how to detect user touches, please see Detecting Touches in Corona.
When the user's finger touches the screen, a hit event is generated and dispatched to display objects in the display hierarchy. Only those objects that intersect the hit location (the location of the finger on the screen) will be candidates for receiving the event.
The events propagate through these objects in a particular order. The first object in the display hierarchy to receive the event is the top-most display object that intersects the hit location; the next object is the next top-most object intersecting the hit location; and so on.
Hit events propagate until they are handled. You can stop propagation to the next object (all listeners of the current object still get the event) by telling the system that the event was handled. This boils down to making a listener return true. If at least one of the listeners of the current object returns true, event propagation ends; the next object will not get the event. If the event is still unhandled at the end of this traversal, it is broadcast as a global event to the global Runtime object.
Hit events are a hybrid of local and global events. They are dispatched to a single display object at a time, but any listener registered with that display object will receive the event.
In some situations, it is convenient to have subsequent events target the same object that handled the initial touch event (a user's finger initially touching the screen). To accomplish this, you can use a special method display.getCurrentStage():setFocus( object ). When the user's finger is lifted, you can call the method again and pass nil to restore the default behavior.
touch (single touch)
Touch events are a special kind of hit event. When a user's finger touches the screen, they are starting a sequence of touch events, each with different phases.
- event.name is the string
"touch". - event.x is the x-position in screen coordinates of the touch.
- event.y is the y-position in screen coordinates of the touch.
- event.xStart is the x-position of the touch from the "began" phase of the touch sequence.
- event.yStart is the y-position of the touch from the "began" phase of the touch sequence.
- event.phase is a string identifying where in the touch sequence the event occurred:
"began"a finger touched the screen."moved"a finger moved on the screen."ended"a finger was lifted from the screen."cancelled"the system cancelled tracking of the touch.
touch (multitouch)
To illustrate the documentation below, we have provided two new sample projects:
- "MultitouchFingers" (under "Interface")
- "MultitouchButton" (under "Interface")
In addition, we have made minor revisions to ui.lua to support multitouch. If you activate multitouch and plan to use ui.lua, you should include this new version in your project. The new library should also be compatible with non-multitouch cases.
Multitouch in Corona
When multiple touch is enabled, multiple touches are sent as individual touch events, each of which will now behave like single touches even when happening simultaneously. We have also added a time property so that you can detect simultaneous touch events when writing gesture-recognition code. Finally, we have added an id property which allows you to track which touch events came from the same finger.
Note: Multitouch does not work correctly on some Android devices (e.g., NexusOne, HTC Incredible, etc.). This can be demonstrated in Drag Me Multitouch sample app. This is a limitation of the current Android platforms and not Corona.
Whether or not multitouch is enabled, touch events will have the following standard properties:
- event.x is the x-position in screen coordinates of the touch.
- event.y is the y-position in screen coordinates of the touch.
- event.xStart is the x-position of the touch from the "began" phase of the touch sequence.
- event.yStart is the y-position of the touch from the "began" phase of the touch sequence.
- event.phase is a string identifying where in the touch sequence the event occurred:
- "began" a finger touched the screen.
- "moved" a finger moved on the screen.
- "stationary" a finger is touching the screen but hasn't moved from the previous event.
- "ended" a finger was lifted from the screen.
- "cancelled" the system cancelled tracking of the touch.
- event.id is a unique identifier of the chosen touch so that you can distinguish between multiple touches across events (i.e. the different events sent across multiple listener calls). The id uniquely identifies a given finger touching the screen as that touch changes state, generating new touch events.
- event.time is a timestamp. It is in the same units as returned by
system.getTimer().
Using multitouch
As before, you must explicitly activate multitouch before you will receive multiple touch events:system.activate( "multitouch" )
Once this call is made, you will get multiple touch events delivered as individual single touch events. For example, if two fingers moved simultaneously, Corona will hit-test each touch separately, delivering them to the respective listeners; both events will have the same timestamp.
Multiple Focus, Buttons and Delivery Precedence
In the single-touch world, we provided the ability to have touch events target a particular object via the stage:setFocus(object) method, which caused all future touch events to be sent directly to the touch listener for that object. This made behaviors like button rollovers possible. The typical flow, as seen in the previous ui.lua library, was:
- The initial touch hit-tests the object, so the touch event is dispatched to object's touch listener
- Hit-testing for all future touches is (globally) disabled by the object's touch listener, which calls stage:setFocus(object). This causes future touch events to be forwarded to that object, rather than go through hit-testing against other objects.
- When the touch ends (or is cancelled), normal hit-testing is restored via
stage:setFocus( nil ).
In a multitouch world, this model breaks down, because it assumes there will only be one unique touch at a time. As a result, two buttons couldn't be pressed simultaneously.
Therefore, we had to add the ability to forward a touch event on a per-object basis. To do this, we extended the event with a parameter that uniquely identifies the event associated with a given finger touching the screen:
stage:setFocus( object [,touchID] )
Calling the above with only one parameter (the object) is the same as the old global focus behavior: all touches will be forwarded to the same object.
Calling the above method with the optional parameter (the touchID) means that the specified touch has focus on that object, but other touches do not. Using this API, it is possible to create an object that will “own” the first touch it gets, for the lifetime of that touch, and for multiple objects to obtain their own focused touches at the same time. See the “GettingStarted/FollowMeMultitouch” sample code for a demonstration of this behavior.
To turn off per-object focus, you specify the object and pass nil for the touchID:
stage:setFocus( object, nil )
Note: for backwards compatibility, stage:setFocus() reverts to the old setFocus behavior when multitouch is off:
stage:setFocus( obj, nil )behaves likestage:setFocus( nil )stage:setFocus( obj, id )behaves likestage:setFocus( obj )
As a result, the latest ui.lua library code, distributed with Beta 6 or later, should work as expected in both multitouch and non-multitouch modes.
Gesture support
See the "Multitouch" sample code in the iPad sample code directory for an example of how to implement a pinch/zoom gesture.
We intend to provide additional framework libraries to make gesture recognition easier, but we encourage you to experiment with multitouch in the meantime.
Custom Events
In Corona, you can register custom events with both display objects and the global Runtime object. In both cases, you will have to manually dispatch the event yourself using the following object method:
object:dispatchEvent( event )
Dispatches event to object. The event parameter must be a table with a name property which is a string identifying the type of event. The object parameter must be either a display object or the global Runtime object. If object has a listener registered to receive name events. We recommend you also include a target property to the event so that your listener can know which object received the event.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -- Create an object that listens to events local image = display.newImage( "image.png" ) -- Setup listener local myListener = function( event ) print( "Event " .. event.name ) print( "Target has width: " .. event.target.stageWidth ) end image:addEventListener( "myEventType", myListener ) -- Sometime later, create an event and dispatch it local event = { name="myEventType", target=image } image:dispatchEvent( event ) |
Replies
In creating a "touch" listener, is there anyway to determine which object is the focus of the event in the listener function? For example,
table =
{
{ value=10, image=display.newImage(group1, "file1.png") },
{ value=20, image=display.newImage(group1, "file2.png") }
}
for i, v in ipairs(table) do
v.image:addEventListener("touch", UpdateScore)
end
function UpdateScore(event)
if ( event.phase == "ended" ) then
score = score + object.value --somehow update the score based on which object is receiving the event
end
end
You can determine which object was touched by using event.target. If the target has properties associated with it, such as a value or id, then you can retrieve those using event.target.value or event.target.id. Here's a simplified example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | local score = 0 myObject1 = display.newImage("file1.png", 50, 50) myObject2 = display.newImage("file2.png", 150, 150) myObject1.value = 10 myObject2.value = 20 function UpdateScore(event) local t = event.target if ( event.phase == "ended" ) then score = score + t.value --update the score print("score: ".. score) --print the score to the terminal end end myObject1:addEventListener("touch", UpdateScore) myObject2:addEventListener("touch", UpdateScore) |
Thank you! That was what I needed to know.
-Kelly
Thanks Gilbert... that code helped me a lot... thanks...
Can someone explain the difference between a touch and tap event?
Also, is there any support or sample code for a double-tap event?
Thanks!
initial sample code for a table listener gives a syntax error if the function on the table is declared as local:
should
1 2 3 4 | local function button:touch(event) print(event.name.."occurred") return true end |
not be
1 2 3 4 | function button:touch(event) print(event.name.."occurred") return true end |
?
I am experiencing the same - is the sample code wrong ?
What is the impact of NOT making these event functions "local" ?
The table listeners samples on this page that are defined with "local" are wrong and shouldn't have "local". The objects have already been defined and the table listener is only adding the method to table/object. I fixed the samples.
Hi all,
I have question about using dispatchEvent to change screens using the viewController supplied with the tab bar example. I used that as my base because it fit my application ui that I envisioned quite well. However, now I am at a point where I need to automatically return to my last screen after having selected a different tab. For example: I am in screen 1 then I switch to screen 2 where I am presented with some choices and, once selected, I want to automatically return to screen 1 without having to touch the tab bar. When I try to dispatch the event my code looks like this:
local event = { name="touch", phase="ended", id=2, target = tabBar }
Runtime:dispatchEvent(event)
I thought that, perhaps I needed to pecify tabBar.tab[1] but that gives me an index error.
Admittedly, I am a noob at this but I have been programming for 30 years so I'm a little frustrated at not figuring this one out yet.
Any help would be immensely appreciated.
Hmm.. I think this documentation also include why and when a "return true" should be included on an event listener..
I have to go to a forum to have it answered. Instead of just looking on the documentation.
Cheers!
Third paragraph under "Touch Events" on this page:
"If at least one of the listeners of the current object returns true, event propagation ends; the next object will not get the event. If the event is still unhandled at the end of this traversal, it is broadcast as a global event to the global Runtime object."
I think, they were not there before. ^_^ That's why my comment. and after some weeks I saw the explanation. Its either I missed it... Or they have updated it.
anyway.. as long its there now.. its nice.
It says above in the docs that "Whether or not multitouch is enabled, touch events will have the following standard properties" and includes event.id as one of these properties... but is this really true when multitouch is not enabled? If so, why?
couldnt see anything about changing gravity with orientation.
I'm just starting out with Corona and thought I'd share this.
1 2 3 4 5 6 7 8 9 10 11 12 13 | gaOrientationGravity = { portrait = {x=0,y=-1}, portraitUpsideDown = {x=0,y=1}, landscapeLeft= {x=1,y=0}, landscapeRight = {x=-1,y=0} } local function onRotation( poEvent ) local aVector aVector = gaOrientationGravity[poEvent.type] physics.setGravity( 10 * aVector.x, -10 * aVector.y ) end Runtime:addEventListener( "orientation", onRotation ) |
Hi,
How often is a "touch" listener called if the user keeps pressing?
Is it once per frame?
The "touch" listener only hits once per event. Once when you "began" the touch," as many times as the touch is "moved" (assume this will fire multiple times if the user's finger is big or not steady and the screen is sensitive, etc.) and once again when the touching has "ended."
Personally, I've never seen the "cancelled" event fired, so I'm curious as to when and how we can make that happen.
The "cancelled" event comes from Apple's documentation and according to their information would occur if your app was interrupted. I've never seen that event occur either.
The best way to learn about touch events is to run the DragMe or DragMeMultitouch sample apps and look at the print messages in the terminal as you touch the screen.
Can't remember where I read it, but is it true that in a multi-touch mode, event.time is the same value for the different event.id's ?






If an object has event listeners, is it necessary to remove them if the object is removed from a display group?
In other words, do event listeners NEED to be tidied up?