轻触 / 触摸 / 多点触摸

本指南解释了轻触触摸多点触摸之间的区别,以及如何处理与每种方法相关的事件。

如果您是 Corona 新手,并且尚未了解基本的屏幕交互和事件,请先阅读基本交互和事件检测指南。

轻触检测

轻触事件是最基本的屏幕交互形式。本质上,轻触是指用户触摸屏幕并在 تقریباً 同一点抬起手指。仅当用户在该点触摸释放时,轻触事件才被视为成功。

在 Corona 中,您可以通过在大多数常见的显示对象上注册 "tap" 事件监听器来监听轻触事件。

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

从轻触返回的 event 属性包括:

触摸事件不同,轻触事件不包含 phase 属性 — 轻触是涉及触摸和释放的单一操作,因此您无需以任何特殊方式处理阶段。

过滤多次轻触

使用 event.numTaps 属性,您可以轻松确定某个对象是否被多次轻触,并同时忽略该对象的单次轻触。为此,只需确保 event.numTaps 等于 2 或更高,并忽略返回 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 )

触摸检测

触摸事件提供了更高级别的屏幕交互。使用触摸事件,您可以检测用户何时首次触摸屏幕以及何时将触摸从屏幕上抬起。您还可以跟踪触摸在屏幕上移动时的运动轨迹。为此,Corona 在四种状态之一中提供了 event.phase 属性:

您可以通过在大多数常见的显示对象上注册 "touch" 事件监听器来监听触摸事件。

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

从触摸返回的事件属性包括:

多点触摸

在应用中启用多点触摸可以让您同时检测和处理屏幕上的多个用户触摸。

重要

由于默认情况下多点触摸是禁用的,因此您必须首先通过system.activate() 函数启用它。

system.activate( "multitouch" )

多点触摸功能仅在实际移动设备(手机、平板电脑等) 运行 Windows 7 或更高版本的带有触摸屏的系统上受支持,在这种情况下,Windows 版 Corona 模拟器和Corona 构建的 Win32 桌面应用程序.

都支持多点触摸。

-- 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 )

轻触/触摸传播

当用户触摸屏幕时,事件将分派到显示层次结构。只有与屏幕上触摸位置相交的显示对象才会接收该事件。

轻触触摸事件按特定顺序在这些对象中传播。默认情况下,第一个接收事件的对象是显示层次结构中与触摸位置相交的最前面显示对象。下一个接收事件的对象是层次结构中与触摸位置相交的下一个对象,依此类推。

轻触和触摸事件会一直传播,直到被“处理”为止。这意味着,如果您在显示层次结构中有多个对象相互重叠,并且每个对象都应用了轻触或触摸事件侦听器,则该事件将传播通过所有这些对象。但是,您可以通过告诉 Corona 该事件已被处理来停止向下一个基础对象的传播。这就像从事件侦听器返回 true 一样简单 — 这将停止传播周期并阻止任何基础对象响应命中事件。

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 )

如果在遍历整个显示层次结构后仍未处理轻触或触摸事件,则它将作为全局事件广播到运行时侦听器。

设置触摸焦点

您可以通过在对象上设置焦点来将所有触摸事件定向到特定显示对象。这将指示系统将所有未来的触摸事件传递给该对象,有效地使其“拥有”它在其生命周期内接收的第一个触摸。

考虑一个典型的按钮 — 如果用户触摸按钮并在不抬起/释放触摸的情况下滑出按钮边界,则该按钮可能不应在触摸释放时触发操作。同样,如果触摸从按钮上滑落并与另一个触摸敏感对象相交,您可能不希望该对象做出反应,因为触摸是从按钮开始的。通过在显示对象上设置焦点,可以轻松解决这两种情况。

要设置显示对象的焦点,请将其对象引用传递给StageObject:setFocus()。这可以是触摸侦听器中的 event.target,也可以是对对象本身的任何直接引用。

相反,当您希望释放对象上的焦点时,只需将 nil 传递给StageObject:setFocus()即可。

display.getCurrentStage():setFocus( nil )

此示例显示了如何处理多个对象的焦点和释放:

-- 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 )

多点触摸焦点

当通过system.activate()启用多点触摸时,也可以实现触摸焦点。但是,由于同一对象上可能存在多个触摸,因此您必须通过唯一的内部标识符来专用它接收的第一个触摸。这是通过将从触摸侦听器收集的 event.id 属性作为第二个参数传递给StageObject:setFocus()来完成的。

display.getCurrentStage():setFocus( event.target, event.id )

然后,当您希望释放对象上的焦点时,只需将 nil 作为第二个参数传递给StageObject:setFocus()即可。

display.getCurrentStage():setFocus( event.target, nil )

此示例显示了如何在启用多点触摸时处理多个对象的焦点和释放:

-- 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 )