如果看過sample中touch的代碼,你會發現示例中有一個cc.NODE_TOUCH_CAPTURE_EVENT事件,它和cc.NODE_TOUCH_EVENT觸摸事件一樣,是引擎級別的事件,我們來看看它和觸摸事件的區別。
首先觸摸捕獲事件默認是開啓的,即setTouchCaptureEnabled(true)
觸摸捕獲事件的優先級要比觸摸事件要高,換句話說,觸摸捕獲事件會比觸摸事件先響應,並且有權不分發給觸摸事件響應。
對於一個完整的捕獲+觸摸事件,有這麼一個流程:
1.捕獲階段,一旦有觸摸事件發生,那麼首先會觸發捕獲事件,並且捕獲順序是從zOrder高到低,越在屏幕上方越優先捕獲。從父節點傳到子節點,父節點優先捕獲。
2.目標階段,該階段就是各個節點響應自己的觸摸事件,began,moved,ended等。
3傳遞階段,只要當前節點沒有將觸摸吞噬,那麼觸摸事件將會繼續往下層的節點進行傳送。
有了一些理論知識,我們來實際操作一下,寫些代碼,
function MyScene:ctor()
local layer = display.newLayer()
self:addChild(layer)
layer:setTouchEnabled(true)
layer:setTouchSwallowEnabled(false)
layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
if event.name == "began" then
print("layer began")
elseif event.name == "moved" then
print("layer moved")
elseif event.name == "ended" then
print("layer ended")
end
return true
end)
layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("layer capture began")
elseif event.name == "moved" then
print("layer capture moved")
elseif event.name == "ended" then
print("layer capture ended")
end
return true
end)
local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)
layer:addChild(sp)
--self:addChild(sp)
sp:setTouchEnabled(true)
sp:setTouchSwallowEnabled(false)
sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
if event.name == "began" then
print("sp began")
elseif event.name == "moved" then
print("sp moved")
elseif event.name == "ended" then
print("sp ended")
end
return true
end)
sp:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("sp capture began")
elseif event.name == "moved" then
print("sp capture moved")
elseif event.name == "ended" then
print("sp capture ended")
end
return true
end)
end
代碼中,添加了兩個節點,一個是layer,一個sprite,sprite添加在layer上,他們都開啓了觸摸,沒有吞噬觸摸,並且添加了捕獲事件和觸摸事件,返回值爲true。簡單點擊一下窗口,看看print信息,
因爲父節點會優先捕獲事件,所以首先是layer捕獲到了,其次子節點捕獲到,接下來是處理觸摸,因爲子節點在父節點的上面,所以子節點先響應了觸摸事件,處理過後由於沒有吞噬觸摸,所以會繼續將觸摸事件向下傳遞,此時它的下面就是它的父節點laier,所以layer又再一次捕獲到了這個事件,最後layer開始響應觸摸事件。
如果我們將子節點sprite設置吞噬觸摸,
可以看到,當sprite響應了觸摸事件之後就不再向下傳遞了,所以父節點就不能再捕獲到上方傳下來的觸摸了。
我們再修改一下代碼,把layer的捕獲事件返回爲false,sprite還是依然保持吞噬觸摸,也就是在之前的代碼上做這樣的修改,
layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("layer capture began")
elseif event.name == "moved" then
print("layer capture moved")
elseif event.name == "ended" then
print("layer capture ended")
end
return false
end)
local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)
layer:addChild(sp)
--self:addChild(sp)
sp:setTouchEnabled(true)
--sp:setTouchSwallowEnabled(false)
sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
我們運行一下,點擊屏幕看下效果,
這裏我是擡起了鼠標後截出來的日誌信息,可以看到,layer的捕獲開始打印了兩次。
由於我們在父節點layer的捕獲事件中,將其設置成返回false,所以其子節點是無法響應後面的觸摸事件的,但是關鍵的是,即便父節點在捕獲階段阻止響應事件,但子對象仍然可以捕獲到事件,只是不會觸發事件,說白了就是,父節點阻斷了捕獲,但是我子節點依然可以捕獲到,只是子節點的捕獲不響應各個事件,也不會再讓後面的觸摸事件響應。
所以我們回過來想一下,第一次觸摸屏幕,父節點捕獲到了,子節點也捕獲到了,但是返回false,所以子節點的捕獲事件不觸發,所以看不到sprite打出捕獲信息,並且sprite也不響應觸摸事件,所以吞不吞噬也就沒作用了,繼續分發着走,那麼layer就會再一次捕獲到自己的事件,只是這次返回的false,它把它自己的後面的觸摸事件也停止了。所以ended事件響應我們一個都看不到。
不知道大家有沒有理清思路,這次我們不把sprite添加在layer上,sprite也添加在scene中,我們來看下結果,
function MyScene:ctor()
local layer = display.newLayer()
self:addChild(layer)
layer:setTouchEnabled(true)
layer:setTouchSwallowEnabled(false)
layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
if event.name == "began" then
print("layer began")
elseif event.name == "moved" then
print("layer moved")
elseif event.name == "ended" then
print("layer ended")
end
return true
end)
layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("layer capture began")
elseif event.name == "moved" then
print("layer capture moved")
elseif event.name == "ended" then
print("layer capture ended")
end
return true
end)
local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)
--layer:addChild(sp)
self:addChild(sp)
sp:setTouchEnabled(true)
sp:setTouchSwallowEnabled(false)
sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
if event.name == "began" then
print("sp began")
elseif event.name == "moved" then
print("sp moved")
elseif event.name == "ended" then
print("sp ended")
end
return true
end)
sp:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("sp capture began")
elseif event.name == "moved" then
print("sp capture moved")
elseif event.name == "ended" then
print("sp capture ended")
end
return true
end)
end
觸摸吞噬都關閉,各個事件返回值都是true,print的結果是,
因爲sprite後添加,他們在同一個zOrder上所以sprite要靠前,先捕獲到事件,然後到觸摸事件,做完之後傳遞到下面的layer,layer開始捕獲然後處理觸摸事件。
這就是quick對於捕獲事件的原理了。如有錯誤,歡迎指出。