taptouch-featMost Corona developers understand the concept behind tap and touch events, but the lines get a little blurry when dealing with more complex scenarios, for example overlapping objects with different types of event listeners. Today’s tutorial explains exactly how Corona handles these events and which events are broadcast to which objects.

Tap vs. Touch

Let’s quickly discuss the basics for users who may be new to Corona SDK or mobile development in general. When the user touches the screen of a mobile device, this action is regarded in one of two ways:

  1. “tap” — this event 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.
  2. “touch” — these 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.

This tutorial won’t go into depth about the properties returned from these events — if you need to explore this topic further, please refer to our guide.

Event Distinction

Looking beyond the basic concept of tap vs. touch, we’ll explore how Corona handles these events. At the core level, it’s important to understand that each type is regarded as distinct. You may think that a screen touch is just a screen touch, but the difference will become more apparent as we examine more complex examples.

Test Project Setup

For purposes of this tutorial, let’s quickly set up two squares on the screen that overlap in the center. We’ll use these squares to test different types of listeners, and explore how/when the events are processed. Let’s also place a text label on each rectangle so we can observe which type of listener is associated with each rectangle.

Tap on Tap

Working with this example, let’s explore the most simple case of overlapping objects: one tap object overlapping another tap object. When you click in the middle overlapping section and observe the output in the Terminal/console, you’ll notice that, by default, tap events transmit through — or “propagate” through — to underlying objects.

This is by design, but how do you prevent this from occurring when such behavior is not desired? The solution is to simply return true at the end of the listener function of the “active” object, in this case the front square. This will prevent the tap event from reaching the back square entirely.

Now test this in the Terminal/console and you’ll notice that the tap only reaches the front square, while the back square remains blocked, at least in the region where the front square overlaps it.

Touch on Touch

As expected, the same principle applies to touch events. Let’s return true at the end of our touch event listener function exactly as we did for the tap listener. We must also change both squares to touch objects instead of tap objects:

Test the updated project and the output in the Terminal/console should look similar to this:

Tap on Touch / Touch on Tap

Things get a little more complicated when you have objects with different listener types overlapping each other, but you still need to control the propagation of tap and touch events. For testing purposes, let’s adjust the sample project so it becomes a tap object over a touch object:

Test this code in the Terminal/console, and the output should look similar to this:

Notice that the back square still receives touch events despite the fact that we’ve returned true in both the tap and touch listener functions. This is why it’s important to understand — as noted earlier — that tap and touch events are actually distinct from Corona’s standpoint, despite some similarities from the user’s standpoint.

The behavior is similar if we change the test case to a touch object over a tap object:

Working with Overlaps

The above examples of overlapping objects with different listener types is fairly common in app development, so you’ll need an approach to handle these situations. Some examples include:

  1. tap objects over a larger region that must detect touch-moves, i.e. stationary buttons placed over a background that can be scrolled/moved as the user touches and drags it.
  2. a draggable touch object that can be moved around over underlying tap objects that the user can tap on to collect/activate.

For both of these cases, there is a tactic to prevent the “wrong type” of event from propagating through to an underlying object with a different listener type, as follows:

1. Isolate Events on Overlaying Tap Object

In the instance where a tap object resides over a touch object, you can add a listener of both types (tap and touch) to the front object and then use a conditional check in the listener function to void events of the undesired type:

In the comboListener function, conditionally check that event.phase exists (or in this case, does not exist). Since tap events do not return any phase property, detecting its absence reveals that the event is a touch. In addition, we use the setFocus() method in the touchListener function to give focus to the background object — but only if it receives the touch from user interaction outside of the front object’s bounds.

2. Isolate Events on Overlaying Touch Object

Similar to the above method, you can isolate events to an overlaying touch object by applying both listener types to the touch object and processing only events with a phase property, revealing that it’s a touch:

In Summary

Every project will vary slightly in the exact way that it should behave in regards to tap and touch, but understanding these core concepts is essential to the ultimate user experience. Experiment with the different types and phases, and always remember to test, test, and test again!


Tutorial: Tap/Touch Anatomy