天天看點

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

從一次微信聊天開始

前兩天正在愁公衆号寫點什麼,打開微信看到uikiller使用者「悅雨」遇到了一個問題:

地圖拖動與子節點觸摸事件産生沖突,表現為:在子節點上拖動,但地圖不動,怎麼辦?

一句話不太好描述問題,在征得「悅雨」同意後,将這次交流的内容截圖出來:

第一話

問題描述

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

第二話

ScrollView解決方案

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

在與「悅雨」的交流過程中,我用ScrollView+TileMap+Button+AudioSource花了五分鐘做了一個小測試,将TiledMap放在ScrollView中,在TiledMap中又放值了一個按鈕,驗證了一下曾經的經驗是否任然有效。

第三話

結果是OK的,于是将測試場景發給了「悅雨」同學,但ScrollView不是想要的,繼續聊這個問題:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

第四話

不想用ScrollView,還有什麼方案呢?觸摸事件捕獲!繼續對話:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

至此問題終于解決,下來的公衆号内容也有了着落

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

快速原型測試

有了上面這個案例,今天就以這個地圖場景為例,看看不寫代碼,利用引擎内置元件,如何快速實作一個原型或元件測試 ,請看下面視訊:

溫馨時提示:因為是在辦公室錄制的視訊,有許多幹擾的聲音,視訊裡沒有語音解說,采用的文字說明,請觀看視訊的時候留意文字。

從視訊中可以看到,使用按鈕元件,可以調用任意節點下的元件函數(無參數的),利用好這個功能,可以少寫不少的代碼。

從源碼中學習

當知道ScrollView中拖動,不會觸發子節點的事件,到此是不是就完了呢?有沒想過,ScrollView它是怎麼做的呢?帶着好奇心,我們一起再深入一下ScrollView,它上面有一個關鍵屬性,請看下圖:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

有了Cancel Inner Event這個線索,我們直接從ScrollView元件源碼入手,看看它是怎麼實作的。

以cc.ScrollView元件為例,看如何定位元件源碼:

  1. 使用Chrome浏覽器啟動遊戲預覽
  2. 打開Chrome DevTools工具
  3. 鍵盤快捷鍵:ctrl + p 或 cmd + p
  4. 輸入:ccscrollview (引擎元件原檔案名公式:cc + 元件名)
  5. 從顯示的清單上找到要檢視的源碼檔案
CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

選擇CCScrollView.js檔案,自動跳轉到Sources标簽,打開檔案内容,鍵入ctrl + f 或 cmd + f 在目前檔案中搜尋:cancelInnerEvents,找到關鍵代碼:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話
  1. 可以看到976行中,當

    this.cancelInnerEvents

    變量為真可能會執行到下面的代碼,設定成員變量

    this._touchMoved=true

  2. 再看1006行onTouchEnd函數,在這裡判斷了touchMoved這個變量,停止TOUCH_END事件的傳播,這樣子節點的觸摸事件就不會被觸發了
  3. 993行onTouchMoved函數最後一行代碼

    this._stopPropagationIfTargetIsMe(event)

    它是在有條件地停止TOUCHMOVE事件的傳播。

通過上面的分析,再通過斷點跟蹤,在ScrollView和Button元件中分别打上斷點,我們在Button元件上做點選,ScrollView元件的_onTouchEnded居然先被斷下來,它是怎麼做到的呢?

在CCScrollView.js源碼中搜“TOUCH_END”關鍵字,找到TOUCH事件注冊的代碼:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

看看這裡有與自己平時注冊TOUCH事件有什麼不同?相信你已經發現了,關鍵在最後一個參數:useCapture,用于是否捕獲子節點事件,又稱之為向下冒泡(預設是向上冒泡),下面以TOUC_END事件為例,簡單說明一下:

this.node.on(
  cc.Node.EventType.TOUCH_END,   //觸摸事件類型
  this._onTouchEnded,            //事件處理函數
  this,                          //事件處理函數的this上下文(使用箭頭函數時通常被省略)
  true                           //是否捕獲子節點Touch事件
);           

複制

為了幫助大家更好地了解,我做了個簡單的小元件,請看代碼:

cc.Class({
    extends: cc.Component,
    properties: {
        useCapture: false, //是否啟用捕獲
    },
    onLoad () {
        this.node.on(
            cc.Node.EventType.TOUCH_END,
            () => cc.log('touchend', this.node.name), //測試時觀察日志輸入出
            this, 
            this.useCapture
        );
    }
});           

複制

把這個元件挂到兩個父子關系的節點上,在父節點上開啟捕獲,看下面截圖:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

運作點選紅色節點,看看日志輸出:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

從日志中看到白色節點先響應,然後是紅色節點,我們把白色父節點的UseCapture關閉,再看看日志輸出:

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

這次是紅色子節點先響應,白色父節點後響應,更多細節可以參考Cocos Creator官方文檔:

https://docs.cocos.com/creator/manual/zh/scripting/internal-events.html?h=%E5%86%92%E6%B3%A1

還有對應的官方範例:TouchPropagation

CreatorPrimer|觸摸事件冒泡從一次微信聊天開始第一話第二話第三話第四話 快速原型測試從源碼中學習題外話

題外話

這次除了教程,還想再聊一個事情,經常會有同學通過微信、QQ、公衆号向Shawn咨詢問題,首先感謝大家對shawn的信任,如果是在自己的能力範圍内且對大家幫助的内容,Shawn一定真誠對待,這也正是「奎特爾星球」内容的重要來源。但是因為個人能力和時間有限,不是每一個人的問題Shawn都能解答,還望大家見諒。

微信、QQ很容易讓人在工作時分心,一般在做事的時候會将手機靜音或離遠一點,公衆号上偶爾也收有留言,但有時會忘記去公衆号上檢視,超過24小時的留言,看到了想回複也無沒辦法,很是無奈。

為了能把公衆号做好,Shawn特地定制了一個域名:creator-star.cn以及專用郵箱:[email protected],歡迎大家向公衆号投稿和讨論問題,Shawn需要大家的大家的支援和幫助!