• ‎Cocos2d-x 学习笔记(16) 触摸事件与分发 EventTouch dispatchTouchEvent EventListenerTouch


    1. EventTouch

    触摸事件的成员变量:枚举EventCode、存储Touch的容器。

    不同的EventCode代表不同时机的触摸事件,能让监听器调用不同的回调函数。

        enum class EventCode
        {
            BEGAN,
            MOVED,
            ENDED,
            CANCELLED
        };
        static const int MAX_TOUCHES = 15;
       EventCode _eventCode; std::vector<Touch*> _touches;

    这里涉及到了Touch类:

    Touch类

    封装了一个触摸信息,包括触摸点类型(单点/多点)、坐标、开始坐标、ID、3D触控压力等。有set get方法。

    2. EventListenerTouch

    触摸事件监听器根据触摸点touch类型的不同,分为单点触摸监听器/多点触摸监听器。

    2.1 EventListenerTouchOneByOne

    单点触摸监听器回调函数只能处理触摸事件中一个touch。

    ID统一为:

    const std::string EventListenerTouchOneByOne::LISTENER_ID = "__cc_touch_one_by_one";

    该类4个回调函数,根据触摸事件code不同分类:

    public:
    
        typedef std::function<bool(Touch*, Event*)> ccTouchBeganCallback;
        typedef std::function<void(Touch*, Event*)> ccTouchCallback;
    
        ccTouchBeganCallback onTouchBegan; //开始触摸
        ccTouchCallback onTouchMoved; //触摸并移动
        ccTouchCallback onTouchEnded; //结束触摸
        ccTouchCallback onTouchCancelled; //触摸取消

    该类2个成员变量:

    private:
        std::vector<Touch*> _claimedTouches; //存储处理完BEGAN事件的回调函数的参数touch
        bool _needSwallow; //事件需要吞没,为true时停止事件向其他监听器分发,setSwallowTouches(bool)设置,默认为false

    在add监听器到分发器时,首先需要对该监听器执行checkAvailable()。单点触摸监听器的checkAvailable()中,要求onTouchBegan需要存在。

    2.2 EventListenerTouchAllAtOnce

    多点触摸监听器回调函数能一次处理事件中所有touch。

    ID为:

    const std::string EventListenerTouchAllAtOnce::LISTENER_ID = "__cc_touch_all_at_once";

    4个回调函数:

    public:
        typedef std::function<void(const std::vector<Touch*>&, Event*)> ccTouchesCallback;
        ccTouchesCallback onTouchesBegan;
        ccTouchesCallback onTouchesMoved;
        ccTouchesCallback onTouchesEnded;
        ccTouchesCallback onTouchesCancelled;

    checkAvailable()方法要求4个回调函数都要存在。

    3. dispatchTouchEvent 

    在dispatchEvent方法中,当参数事件为TOUCH类型,调用dispatchTouchEvent进行事件分发。

    该方法首先对2个触摸监听器ID的容器Vector按优先级排序,之后获取触摸事件中所有touch,用容器保存:

    如果2种监听器都存在,isNeedsMutableSet置true。

    然后对单点触摸监听器分发事件

    单点触摸事件分发的逻辑是,把触摸事件的每个touch依次传给所有排好序的单点触摸监听器,监听器执行定义的匿名函数,而不是监听器自带的_onEvent(单点触摸监听器init时_onEvent置nullptr)。

    每个单点触摸监听器执行的回调函数运行流程大致如下:

    简而言之,根据触摸事件code决定执行哪种回调函数,开始触摸对应的回调函数处理touch,对处理好的touch存储到监听器容器,以便还是该监听器执行后续的移动触摸/结束触摸的回调。移动触摸对应的回调函数处理touch。结束触摸对应回调函数处理touch,并从监听器touch容器删除开始触摸的touch,说明整个触摸流程结束了。

    我们知道,当某个监听器的回调函数返回true时,事件将停止分发到后续监听器。

    在单点触摸的监听器中,回调函数返回true时有2个情况:触摸事件停止/触摸事件被回调函数处理完成+已注册+监听器设置true吞没标志。

    在单点触摸的监听器中,回调函数返回false时有这些情况:开始触摸的回调函数没有处理完事件/监听器对开始触摸没有回调方法/移动或结束触摸事件分发到无(对应的)开始触摸数据的监听器。

    当事件停止,会直接退出当前分发,结束分发。

    接下来对多点触摸监听器分发事件

    多点触摸事件分发的逻辑是,每个需要多点触摸的touch已经存储在容器mutableTouches中,容器传给所有排好序的多点触摸监听器,监听器执行定义的匿名函数,而不是监听器自带的_onEvent(多点触摸监听器init时_onEvent置nullptr)。

    单点触摸是将每个touch依次分发到所有监听器,多点触摸是将所有touch分发到所有监听器。

    分发到事件的多点触摸监听器的匿名回调函数:通过对触摸事件code的判断,决定要执行自己监听器的哪个回调函数。当事件停止返回true,停止后续监听器接收事件。

    4. 触摸事件分发时的Touch*容器 originalTouches mutableTouches

    两个容器开始时都存储了本触摸事件的所有touch。

    事件分发到单点触摸监听器,是遍历originalTouches,获取每个touch,再分发touch到监听器。

    单点触摸回调函数中,如果一个touch在某个单点触摸监听器中处理完成,且_needSwallow为true,且存在多点触摸监听器,此时要从mutableTouches删除该touch。原因是_needSwallow为true说明本touch处理完后不再继续分发,而mutableTouches是需要分发到多点触摸监听器,故从mutableTouches中删除该touch。mutableTouches中的迭代器自动指向下一位。同时isSwallowed置true,即不用执行++mutableTouchesIter,迭代器已经实现了++操作。

    还是上面的情况,如果没有多点触摸监听器,isSwallowed默认false,匿名回调函数返回true,停止本touch分发。接下来执行++mutableTouchesIter,和originalTouches一致。

    简而言之,mutableTouches只在有多点触摸监听器的情况下可能发挥它独特的作用(只保存需要接下来多点触发的touch),否则和originalTouches无异,只是存储所有touch而已。

             if (isClaimed && listener->_isRegistered && listener->_needSwallow) //如果事件处理完成,监听器注册状态, 监听器吞没
                    {
                        if (isNeedsMutableSet) //单点多点触摸的监听器都有
                        {
                            mutableTouchesIter = mutableTouches.erase(mutableTouchesIter); //删除此触摸点信息
                            isSwallowed = true; //
                        }
                        return true;
                    }

           if (!isSwallowed)
                 ++mutableTouchesIter;

          //接下来遍历下个touch

  • 相关阅读:
    第五周学习进度报告
    第四周学习进度报告
    第三周大数据学习进度
    十六周总结
    程序员修炼之道-从小工到专家阅读笔记03
    第二阶段冲刺10
    利用正则表达式,分割地址至省市县,更新MySQL数据库数据
    阅读笔记--《大型网站技术架构》—01大型网站概述
    第三周周总结——kettle的简单使用以及MYSQL数据库去重
    热词分析中运用可用性战术
  • 原文地址:https://www.cnblogs.com/deepcho/p/cocos2dx-eventtouch-dispatchtouchevent-eventlistenertouch.html
Copyright © 2020-2023  润新知