大多数 Corona 开发者都理解 **点击** 和 **触摸** 事件背后的概念,但在处理更复杂的场景时,例如具有不同类型事件监听器的重叠对象,界限会变得有些模糊。本教程将详细解释 Corona 如何处理这些事件,以及哪些事件会广播到哪些对象。
让我们快速讨论一下 Corona 或移动开发新手的基本知识。当用户触摸
**点击** — 此事件表示用户快速触摸屏幕并在屏幕上大致相同的点抬起。
**触摸** — 这些事件提供了更高级别的屏幕交互性。使用触摸事件,您可以检测用户何时首次触摸屏幕以及何时从屏幕上抬起触摸。您还可以跟踪触摸在屏幕上移动时的运动。
本教程不会深入探讨这些事件返回的属性 — 如果您需要进一步探讨此主题,请参阅 点击/触摸/多点触控 指南。
除了点击与触摸的基本概念之外,让我们探讨 Corona 如何处理这些事件。在核心层面,理解每种类型都被视为 **不同** 的事件非常重要。您可能认为“屏幕触摸只是屏幕触摸”,但随着我们研究更复杂的示例,差异将变得更加明显。
为了本教程的目的,让我们快速设置一个测试项目,该项目由两个在中心重叠的正方形组成。我们将使用这些正方形来测试不同类型的监听器,并探索事件的处理方式和时间。
打开 Corona 模拟器。
从欢迎窗口中点击 **新建项目**,或从 **文件** 菜单中选择
对于项目/应用程序名称,键入 `TapTouch` 并确保选中 **空白** 模板选项。将其他设置保留为默认值,然后点击 **确定** (Windows) 或 **下一步** (Mac)。这将在您指定的位置(文件夹)中创建测试项目的基本文件。
找到项目文件夹,并在您选择的文本编辑器中打开 `main.lua` 文件。在文件中,将现有行 **替换** 为以下代码:
local backObject = display.newRect( 130, 130, 150, 150 ) backObject:setFillColor( 0.2, 0.4, 0.8 ) backObject.alpha = 0.75 backObject.name = "Back Object" local frontObject = display.newRect( 190, 190, 150, 150 ) frontObject:setFillColor( 1, 0.2, 0.3 ) frontObject.alpha = 0.75 frontObject.name = "Front Object" -- Tap listener function local function tapListener( event ) local object = event.target print( object.name .. " TAP" ) end -- Touch listener function local function touchListener( event ) local object = event.target print( object.name .. " TOUCH (" .. event.phase .. ")" ) end -- Add event listener to back object backObject:addEventListener( "tap", tapListener ) -- Add event listener to front object frontObject:addEventListener( "tap", tapListener )
使用此示例,让我们探讨重叠对象的最简单情况:一个 **点击** 对象与另一个 **点击** 对象重叠。当您在正方形 **重叠** 的中心区域点击/触摸并观察控制台中的输出时,您会注意到(默认情况下)点击事件会传递 — 或“传播” — 到下面的对象。换句话说,前面(红色)的正方形不会阻止点击事件到达后面(蓝色)的正方形,控制台会反映这一点:
Front Object TAP Back Object TAP
这是设计使然,但是当不需要这种行为时,如何阻止它发生呢?解决方案是在关联对象的监听器函数(在本例中为 `tapListener()`)的末尾简单地返回 true
要测试此概念,请将以下行添加到您的代码中:
-- Tap listener function local function tapListener( event ) local object = event.target print( object.name .. " TAP" ) return true -- Prevent propagation to underlying tap objects end
现在刷新/重新加载项目,然后再次在正方形 **重叠** 的中心区域点击/触摸。通过检查控制台,您会注意到点击现在只到达 **前面** 的正方形:
Front Object TAP
正如预期的那样,相同的原则也适用于 **触摸** 事件。让我们在触摸事件监听器函数 (`touchListener()`) 的末尾添加返回 true
-- Touch listener function local function touchListener( event ) local object = event.target print( object.name .. " TOUCH (" .. event.phase .. ")" ) return true -- Prevent propagation to underlying touch objects end
此外,让我们将两个正方形都更改为 **触摸** 对象而不是点击对象,并将它们与 `touchListener()` 函数关联。这可以通过在第 26 行和第 29 行将 `"tap"` 更改为 `"touch"`,并将 `tapListener` 更改为 `touchListener` 来完成。
-- Add event listener to back object backObject:addEventListener( "touch", touchListener ) -- Add event listener to front object frontObject:addEventListener( "touch", touchListener )
刷新/重新加载项目,然后在前面(红色)的正方形上点击/拖动。执行此操作时,请检查控制台,您会注意到如下所示的输出消息:
Front Object TOUCH (began) Front Object TOUCH (moved) Front Object TOUCH (moved) Front Object TOUCH (moved) Front Object TOUCH (moved) ...
当具有不同监听器类型的对象相互重叠,但您仍然需要控制点击和触摸事件的传播时,事情会变得更加复杂。为了测试目的,让我们调整示例项目,使其成为 **点击** 对象(红色正方形)位于 **触摸** 对象(蓝色正方形)之上。通过编辑第 29 行,将 `"touch"` 更改为 `"tap"`,并将 `touchListener` 更改为 `tapListener` 来完成此操作。
-- Add event listener to back object backObject:addEventListener( "touch", touchListener ) -- Add event listener to front object frontObject:addEventListener( "tap", tapListener )
现在刷新/重新加载项目,并在正方形 **重叠** 的中心区域点击/触摸。在控制台中,输出消息可能类似于以下内容:
Back Object TOUCH (began) Back Object TOUCH (ended) Front Object TAP
请注意,尽管我们在 `tapListener()` 和 `touchListener()` 函数中都添加了返回 true
如果我们将示例项目更改为 **触摸** 对象位于 **点击** 对象之上,则行为类似。要测试这一点,请编辑代码如下:
-- Add event listener to back object backObject:addEventListener( "tap", tapListener ) -- Add event listener to front object frontObject:addEventListener( "touch", touchListener )
刷新/重新加载项目,然后再次在正方形 **重叠** 的中心区域点击/触摸。在控制台中,输出消息可能类似于以下内容:
Front Object TOUCH (began) Front Object TOUCH (ended) Back Object TAP
上述具有不同监听器类型的重叠对象的示例在应用程序开发中相当常见,因此您需要一种方法来处理这些情况。一些示例包括:
在必须检测 **触摸** 事件的较大区域上具有 **点击** 监听器的对象,例如放置在背景上的基本
一个可拖动的 **触摸** 对象,可以在用户可以点击以收集/激活的底层 **点击** 对象上四处移动。
对于这两种情况以及许多其他情况,都有一种策略可以防止“错误类型”的事件传播到具有不同监听器类型的底层对象,如下所示:
-- Add event listener to back object backObject:addEventListener( "touch", touchListener ) -- Add two event listeners to front object frontObject:addEventListener( "tap", tapListener ) frontObject:addEventListener( "touch", function() return true; end )
此外,我们可以在 `touchListener()` 函数中使用 `:setFocus()` 方法将焦点赋予背景对象。这很有效,因为由于我们有效地阻止了触摸传播穿过前面的对象,因此它后面的任何触摸对象只有在触摸点位于前面对象的 **边界之外** 时才会获得焦点。
-- Touch listener function local function touchListener( event ) local object = event.target if ( event.phase == "began" ) then display.getCurrentStage():setFocus( object ) elseif ( event.phase == "ended" or event.phase == "cancelled" ) then display.getCurrentStage():setFocus( nil ) end print( object.name .. " TOUCH (" .. event.phase .. ")" ) return true -- Prevent propagation to underlying touch objects end
-- Add event listener to back object backObject:addEventListener( "tap", tapListener ) -- Add two event listeners to front object frontObject:addEventListener( "touch", touchListener ) frontObject:addEventListener( "tap", function() return true; end )
每个项目在点击和触摸方面的行为方式都会略有不同,但理解这些核心概念对于最终用户体验至关重要。尝试不同的类型和阶段,并始终记住测试、测试,再测试!