zoukankan      html  css  js  c++  java
  • cocos2d-x 源代码分析 : EventDispatcher、EventListener、Event 源代码分析 (新触摸机制,新的NotificationCenter机制)

    源代码版本号来自3.x,转载请注明

    cocos2d-x 源代码分析总文件夹

    http://blog.csdn.net/u011225840/article/details/31743129


    1.继承结构

    1.1 结构

          不详吐槽太多,也不贴图了。贴图要审核好久好久好久好久。
          从小到大,先来看下Event的结构。
          1.Event--------EventTouch,EventCustom,EventMouse,EventKeyboard,EventFocus,EventAcceleration
           当中,EventTouch 和 EventCustom是比較特殊的两个Event。EventTouch是3.x版本号的触摸机制相关的Event,而EventCustom则是3.x自己定义事件机制的基础。该机制代替了2.x版本号中的NotificationCenter。

          2.EventListener-------------EventListenerTouchOneByOne,EventListenerTouchAllAtOnce,EventListenerCustom,EventListenerFocus。EventListenerMouse....相应
          相比于Event,Listener多了一个,由于相应的Touch被拆分成了两个Listener。一个是OneByone,一个是TouchAllAtOnce。前者是onTouchBegan等函数的Listener,后者是onTouchesBegan等函数的Listener。



    1.2.EventDispatcher,EventListener,Event三者的关系

           Event相当于data,EventListener包括了data与fuction的一种映射关系,而EventDispatcher相当于一个Manager,管理着EventListener,决定着Event的调用顺序。
           Event中包括了type。target等信息;EventListener包括了ListenerID。相关联的Node。相应的callBack;EventDispatcher里含有各种map,vector来管理不同的Listener。

    详细的,能够看源代码分析。


    2.源代码分析

            本次源代码分析的量比較大,大家要有心理准备哟~

    2.1Event相关

    2.1.1 Event


     enum class Type
        {
            TOUCH,
            KEYBOARD,
            ACCELERATION,
            MOUSE,
            FOCUS,
            CUSTOM
        };
        Type _type;     ///< Event type
        
        bool _isStopped;       ///< whether the event has been stopped.
        Node* _currentTarget;
          
          Event主要包括了三个重要的变量,type,是一个enum变量,里面定义了类型。isStopped定义该event是否已经停止。当一个event发生停止时。与其相关的Listener都要停止callback的调用;currentTarget是与该Event相关联的node。


    2.1.2 EventTouch

        EventTouch是cocos2d-x引擎中很很重要的事件。相应于四种touch操作。该类内部定义了四种EventCode
        
     enum class EventCode
        {
            BEGAN,
            MOVED,
            ENDED,
            CANCELLED
        };

          不同的EventCode能够告诉Listener来调用不同的callback。

           除此之外,EventTouch中含有std::vector<Touch*> _touches 来记录该事件相关的touch,值得注意的是。本版本号默认含有的触摸点最大是5个。


    2.1.3 EventCustom


         EventCustom的出现代替了统治2.x版本号多年的NotificationCenter,来看下EventCustom的两个重要成员变量。

        void* _userData;       ///< User data
        std::string _eventName;

          有没有似曾相识的感觉,还是一样的key。还是一样的userData(有点不一样。原来是CCObject*)。


           其它的Event由于重要性以及使用度的原因,这里不再赘述,假设以后笔者对他们有新的认识。将会在这里进行加入。

    2.2 EventListener相关

    2.2.1 EventListener


         
        std::function<void(Event*)> _onEvent;   /// Event callback function
        Type _type;                             /// Event listener type
        ListenerID _listenerID;                 /// Event listener ID
        bool _isRegistered;                     /// Whether the listener has been added to dispatcher.
    
        int   _fixedPriority;   // The higher the number, the higher the priority, 0 is for scene graph base priority.
        Node* _node;            // scene graph based priority
        bool _paused;           // Whether the listener is paused
        bool _isEnabled;        // Whether the listener is enabled

           重要的成员变量:
          1.onEvent,是绑定于该Listener的callback function,该func的声明使用了c++11的新特性。

          2.type与Event类似。添加一个Unknown的属性。
          3.isRegistered变量很重要,假设他没有被注冊。则他的事件不会触发。
          4.优先级代表了响应一个事件时的顺序。该值越低。越先响应。
          5.node 代表了与该listener相关的node,用于 scene graph类的事件响应,详细的在Dispatcher里面有进行介绍。
          6.最后说下ListenerID,这是该类型事件的标识符。除了EventCustomListener的ListerID是与name相关的。其余的ListenerID都是固定的。用于标识该类EventListener。


         
     /** Enables or disables the listener
         *  @note Only listeners with `enabled` state will be able to receive events.
         *        When an listener was initialized, it's enabled by default.
         *        An event listener can receive events when it is enabled and is not paused.
         *        paused state is always false when it is a fixed priority listener.
         */
        inline void setEnabled(bool enabled) { _isEnabled = enabled; };
    /** Sets paused state for the listener
         *  The paused state is only used for scene graph priority listeners.
         *  `EventDispatcher::resumeAllEventListenersForTarget(node)` will set the paused state to `true`,
         *  while `EventDispatcher::pauseAllEventListenersForTarget(node)` will set it to `false`.
         *  @note 1) Fixed priority listeners will never get paused. If a fixed priority doesn't want to receive events,
         *           call `setEnabled(false)` instead.
         *        2) In `Node`'s onEnter and onExit, the `paused state` of the listeners which associated with that node will be automatically updated.
         */
        inline void setPaused(bool paused) { _paused = paused; };

          上面两段话。解释了什么时候一个Listener是能够接收事件,什么时候是不能够的。
           1.一个Listener想接收事件必须是enabled true 而且 paused false。
          2.值得注意的是,pause的变量专门是为了scenGraph类的事件存在的(兴许有说明),并且一个Node的onEnter和onExit 事件会影响到与Node相关的该类事件的pause状态。

    2.2.2 EventListenerOneByOne


         
        /// Overrides
        virtual EventListenerTouchOneByOne* clone() override;
        virtual bool checkAvailable() override;
        //
    
    public:
        std::function<bool(Touch*, Event*)> onTouchBegan;
        std::function<void(Touch*, Event*)> onTouchMoved;
        std::function<void(Touch*, Event*)> onTouchEnded;
        std::function<void(Touch*, Event*)> onTouchCancelled;

            上面的是OneByOne重载父类的方法。以及自己本身须要被绑定4个callBack 函数。

            
            
    EventListenerTouchOneByOne* EventListenerTouchOneByOne::clone()
    {
    	//深拷贝
        auto ret = new EventListenerTouchOneByOne();
        if (ret && ret->init())
        {
            ret->autorelease();
            
            ret->onTouchBegan = onTouchBegan;
            ret->onTouchMoved = onTouchMoved;
            ret->onTouchEnded = onTouchEnded;
            ret->onTouchCancelled = onTouchCancelled;
            
            ret->_claimedTouches = _claimedTouches;
            ret->_needSwallow = _needSwallow;
        }
        else
        {
            CC_SAFE_DELETE(ret);
        }
        return ret;
    }


    bool EventListenerTouchOneByOne::checkAvailable()
    {
        // EventDispatcher will use the return value of 'onTouchBegan' to determine whether to pass following 'move', 'end'
        // message to 'EventListenerTouchOneByOne' or not. So 'onTouchBegan' needs to be set.
    	//OneByOne仅仅须要onTouchBegan不为空,则能够觉得其是可用的。

    if (onTouchBegan == nullptr) { CCASSERT(false, "Invalid EventListenerTouchOneByOne!"); return false; } return true; }

           什么是可用性,当在dispatcher进行事件分发时,假设一个Listener是不可用的。则不会将该事件分发给他。

        std::vector<Touch*> _claimedTouches;
        bool _needSwallow;

            OneByOne的touch是能够设置吞噬属性的。

    2.2.3 EventListenerAllAtOnce

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

            AllAtOnce就是所谓的standard touch处理机制。一次性处理全部的touch。

           值得注意的是AllAtOnce的checkAvailable要求,上述四个函数指针都不能为空。


           
    bool EventListenerTouchAllAtOnce::checkAvailable()
    {
        if (onTouchesBegan == nullptr && onTouchesMoved == nullptr
            && onTouchesEnded == nullptr && onTouchesCancelled == nullptr)
        {
            CCASSERT(false, "Invalid EventListenerTouchAllAtOnce!");
            return false;
        }
        
        return true;
    }

    2.3 EventListenerCustom


           相同的。EventListenerID是依据独特的Name进行命名的,值得注意的是请确保你的name是具有唯一性的,否在在DispatchCustomEvent时会有问题。


    3. EventDispatcher

           从头到尾写了这么多,才開始进入主题。上面的东西都是为了看EventDispatcher源代码的开胃菜!!!在介绍这个之前,我们必需要看一个内部类

    3.1 EventListenerVector


          
    class EventListenerVector
        {
        public:
            EventListenerVector();
            ~EventListenerVector();
            size_t size() const;
            bool empty() const;
            
            void push_back(EventListener* item);
            void clearSceneGraphListeners();
            void clearFixedListeners();
            void clear();
            
            inline std::vector<EventListener*>* getFixedPriorityListeners() const { return _fixedListeners; };
            inline std::vector<EventListener*>* getSceneGraphPriorityListeners() const { return _sceneGraphListeners; };
            inline ssize_t getGt0Index() const { return _gt0Index; };
            inline void setGt0Index(ssize_t index) { _gt0Index = index; };
        private:
            std::vector<EventListener*>* _fixedListeners;
            std::vector<EventListener*>* _sceneGraphListeners;
            ssize_t _gt0Index;
        };

            首先我要说明的是两个很很重要的变量。fixedListeners和sceneGraphListeners。这是两个截然不同的Listener列表。
            1.sceneGraph类型的事件,是与当前正在执行的scene下node相关的事件,也就是说一个事件(比方说触摸事件),须要依照一定的响应序列。依次对这些Node进行事件响应,所以该类型的事件都会绑定一个与此相关联的node,而且响应顺序是与node在scene下的zorder相关的。该类型下的事件优先级统一为0.
            2.fixed类型的事件相对就比較简单了,可是有一个限制就是其优先级不能为0.

    在EventDispatcher的成员变量中有一个map :std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;  一种ListenerID相应了一个Vector。

           
    size_t EventDispatcher::EventListenerVector::size() const
    {
    	//vector内部的size大小是两个list的和
        size_t ret = 0;
        if (_sceneGraphListeners)
            ret += _sceneGraphListeners->size();
        if (_fixedListeners)
            ret += _fixedListeners->size();
        
        return ret;
    }


    void EventDispatcher::EventListenerVector::push_back(EventListener* listener)
    {
    	//查看listener的priority。假设为0,增加sceneGraphList,否则增加fixedList
        if (listener->getFixedPriority() == 0)
        {
            if (_sceneGraphListeners == nullptr)
            {
                _sceneGraphListeners = new std::vector<EventListener*>();
                _sceneGraphListeners->reserve(100);
            }
            
            _sceneGraphListeners->push_back(listener);
        }
        else
        {
            if (_fixedListeners == nullptr)
            {
                _fixedListeners = new std::vector<EventListener*>();
                _fixedListeners->reserve(100);
            }
            
            _fixedListeners->push_back(listener);
        }
    }

           上面两个函数是与一般Vector不一样的地方。须要注意的地方我已经标注了凝视。



    3.2 Add操作

           既然是一个类似于Manager的类,那就先从Add操作開始吧。


           三种事件的加入方式:

        3.2.1 sceneGraph类

      
    void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
    {
        CCASSERT(listener && node, "Invalid parameters.");
        CCASSERT(!listener->isRegistered(), "The listener has been registered.");
        
    	//检查Listener可用性
        if (!listener->checkAvailable())
            return;
        //设置listener相关属性
        listener->setAssociatedNode(node);
        listener->setFixedPriority(0);
        listener->setRegistered(true);
        
        addEventListener(listener);
    }

    3.2.2 fixed类

         
    void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
    {
        CCASSERT(listener, "Invalid parameters.");
    	//一个事件仅仅能被注冊一次
        CCASSERT(!listener->isRegistered(), "The listener has been registered.");
    	//Fixed类型的事件优先级不能是0
        CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority.");
        
    	//检查可用性
        if (!listener->checkAvailable())
            return;
        
    	//设置关联属性
        listener->setAssociatedNode(nullptr);
        listener->setFixedPriority(fixedPriority);
        listener->setRegistered(true);
        listener->setPaused(false);
    
        addEventListener(listener);
    }

    3.2.3 custom类

    EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)
    {
    	//custom类的事件加入是通过eventName 和 eventcallBack来进行加入的
        EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);
    	
    	//custom的事件优先级被默觉得1
        addEventListenerWithFixedPriority(listener, 1);
    	
        return listener;
    }

       能够看出,加入函数最后都用到了一个函数addEventListener,以下对其进行剖析(这个函数又用到了其它函数。又。又,又。。

    。。

    。)


    3.2.4 addEventListener

    void EventDispatcher::addEventListener(EventListener* listener)
    {
    	//假设当前Dispatcher正在进行事件Dispatch,则放到toAddList中。
        if (_inDispatch == 0)
        {
            forceAddEventListener(listener);
        }
        else
        {
    		// std::vector
            _toAddedListeners.push_back(listener);
        }
    
        listener->retain();
    }

    3.2.5 forceAddEventListener


       
    void EventDispatcher::forceAddEventListener(EventListener* listener)
    {
        EventListenerVector* listeners = nullptr;
        EventListener::ListenerID listenerID = listener->getListenerID();
    	
    	//找到该类eventlistener的vector。此处的vector是EventVector
        auto itr = _listenerMap.find(listenerID);
    	//假设没有找到,则须要向map中加入一个pair
        if (itr == _listenerMap.end())
        {
            
            listeners = new EventListenerVector();
            _listenerMap.insert(std::make_pair(listenerID, listeners));
        }
        else
        {
            listeners = itr->second;
        }
        //将该类别listenerpush_back进去(这个函数调用的是EventVector的pushback哦)
        listeners->push_back(listener);
        
    	//假设优先级是0。则设置为graph。
        if (listener->getFixedPriority() == 0)
        {
    		//设置该listenerID的DirtyFlag
    		//(setDirty函数能够这样理解,每一个ListenerID都有特定的dirtyFlag。每次进行add操作后,都要更新该ID的flag)
            setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY);
            
    		//假设是sceneGraph类的事件。则须要处理两个方面:
    		//1.将node 与event 关联
    		//2.假设该node是执行中的。则须要恢复其事件(由于默认的sceneGraph listener的状态时pause)
    		//添加该listener与node的关联
            auto node = listener->getAssociatedNode();
            CCASSERT(node != nullptr, "Invalid scene graph priority!");
            
            associateNodeAndEventListener(node, listener);
            
    		//恢复node的执行状态
            if (node->isRunning())
            {
                resumeEventListenersForTarget(node);
            }
        }
        else
        {
            setDirty(listenerID, DirtyFlag::FIXED_PRIORITY);
        }
    }

    3.2.6associateNodeAndEventListener

       
    void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener)
    {
    	//将listener与node关联,先从map中找到与该node相关的listener vector
        std::vector<EventListener*>* listeners = nullptr;
        auto found = _nodeListenersMap.find(node);
        if (found != _nodeListenersMap.end())
        {
            listeners = found->second;
        }
        else
        {
            listeners = new std::vector<EventListener*>();
            _nodeListenersMap.insert(std::make_pair(node, listeners));
        }
        //vector内加入该listener,这里的vector 是std::vector
        listeners->push_back(listener);
    }

    3.2.7  removeEventListenersForTarget


         
    void EventDispatcher::resumeEventListenersForTarget(Node* target, bool recursive/* = false */)
    {
    	//恢复Node的执行状态
        auto listenerIter = _nodeListenersMap.find(target);
        if (listenerIter != _nodeListenersMap.end())
        {
            auto listeners = listenerIter->second;
            for (auto& l : *listeners)
            {
                l->setPaused(false);
            }
        }
        // toAdd List中也要进行恢复
        for (auto& listener : _toAddedListeners)
        {
            if (listener->getAssociatedNode() == target)
            {
                listener->setPaused(false);
            }
        }
    	//将该Node 与 node的child 都放到dirtyNode中,来记录与event相关的node
        setDirtyForNode(target);
        
        if (recursive)
        {
            const auto& children = target->getChildren();
            for (const auto& child : children)
            {
                resumeEventListenersForTarget(child, true);
            }
        }
    }

    3.3 Remove

            看完了Add。当然要讲remove

        3.3.1 removeEventListener

         
    void EventDispatcher::removeEventListener(EventListener* listener)
    {
    	//说在前面,移除一个事件的代价比較大,假设没有必要,请不要无故移除事件。
    	//删除一个listener的步骤:
        if (listener == nullptr)
            return;
    
        bool isFound = false;
        
    	//lambda函数。函数从std::vector<EventListener*>* listeners 中移除该listener
        auto removeListenerInVector = [&](std::vector<EventListener*>* listeners){
            if (listeners == nullptr)
                return;
            //遍历
            for (auto iter = listeners->begin(); iter != listeners->end(); ++iter)
            {
                auto l = *iter;
                if (l == listener)
                {
    				//找到后的处理方法,标记状态位,并处理关联Node
                    CC_SAFE_RETAIN(l);
                    l->setRegistered(false);
                    if (l->getAssociatedNode() != nullptr)
                    {
                        dissociateNodeAndEventListener(l->getAssociatedNode(), l);
                        l->setAssociatedNode(nullptr);  // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
                    }
                    //当前没有在分发事件 则直接从listeners中移除该listener(由于标记了状态未。假设此时在分发事件。则会等结束后再移除)
                    if (_inDispatch == 0)
                    {
                        listeners->erase(iter);
                        CC_SAFE_RELEASE(l);
                    }
                    
                    isFound = true;
                    break;
                }
            }
        };
        
        for (auto iter = _listenerMap.begin(); iter != _listenerMap.end();)
        {
    		//从listenersmap 中遍历全部。拿出全部的vector
            auto listeners = iter->second;
            auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
            auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
    
    		//从graphList中寻找。

    找到后须要更新该listenerID的dirty flag。 removeListenerInVector(sceneGraphPriorityListeners); if (isFound) { // fixed #4160: Dirty flag need to be updated after listeners were removed. setDirty(listener->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY); } //从fixedList中寻找 else { removeListenerInVector(fixedPriorityListeners); if (isFound) { setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRIORITY); } } //假设vector在删除后是空的,则须要移除该vector。而且将对应的listenerID从_priorityDirtyFlagMap中移除。 if (iter->second->empty()) { _priorityDirtyFlagMap.erase(listener->getListenerID()); auto list = iter->second; iter = _listenerMap.erase(iter); CC_SAFE_DELETE(list); } else { ++iter; } if (isFound) break; } if (isFound) { CC_SAFE_RELEASE(listener); } //假设在上述过程中未找到。则从toAddList中寻找 else { for(auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); ++iter) { if (*iter == listener) { listener->setRegistered(false); listener->release(); _toAddedListeners.erase(iter); break; } } } }


    3.3.2  removeEventListenersForListenerID


     
    void EventDispatcher::removeEventListenersForListenerID(const EventListener::ListenerID& listenerID)
    {
        auto listenerItemIter = _listenerMap.find(listenerID);
        if (listenerItemIter != _listenerMap.end())
        {
            auto listeners = listenerItemIter->second;
            auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
            auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
            
    		//啊哦 又是一个lambda函数。将std::vector<EventListener*>* listenerVector中的Listener所有移除
            auto removeAllListenersInVector = [&](std::vector<EventListener*>* listenerVector){
                if (listenerVector == nullptr)
                    return;
                
                for (auto iter = listenerVector->begin(); iter != listenerVector->end();)
                {
    				//设置要删除的listener状态,清空与其相关的node信息
                    auto l = *iter;
                    l->setRegistered(false);
                    if (l->getAssociatedNode() != nullptr)
                    {
                        dissociateNodeAndEventListener(l->getAssociatedNode(), l);
                        l->setAssociatedNode(nullptr);  // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
                    }
                    
                    if (_inDispatch == 0)
                    {
                        iter = listenerVector->erase(iter);
                        CC_SAFE_RELEASE(l);
                    }
                    else
                    {
                        ++iter;
                    }
                }
            };
            
    		//两种类型的事件哦
            removeAllListenersInVector(sceneGraphPriorityListeners);
            removeAllListenersInVector(fixedPriorityListeners);
            
            // Remove the dirty flag according the 'listenerID'.
            // No need to check whether the dispatcher is dispatching event.
            _priorityDirtyFlagMap.erase(listenerID);
            
            if (!_inDispatch)
            {
                listeners->clear();
                delete listeners;
                _listenerMap.erase(listenerItemIter);
            }
        }
        
    	//toAddList 的清理,真可怜,还没来得及进入家门就要被扫地出门了么。。。。
        for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end();)
        {
            if ((*iter)->getListenerID() == listenerID)
            {
                (*iter)->setRegistered(false);
                (*iter)->release();
                iter = _toAddedListeners.erase(iter);
            }
            else
            {
                ++iter;
            }
        }
    }

         与其相关的两个remove函数

        
    void EventDispatcher::removeEventListenersForType(EventListener::Type listenerType)
    {
        if (listenerType == EventListener::Type::TOUCH_ONE_BY_ONE)
        {
            removeEventListenersForListenerID(EventListenerTouchOneByOne::LISTENER_ID);
        }
        else if (listenerType == EventListener::Type::TOUCH_ALL_AT_ONCE)
        {
            removeEventListenersForListenerID(EventListenerTouchAllAtOnce::LISTENER_ID);
        }
        else if (listenerType == EventListener::Type::MOUSE)
        {
            removeEventListenersForListenerID(EventListenerMouse::LISTENER_ID);
        }
        else if (listenerType == EventListener::Type::ACCELERATION)
        {
            removeEventListenersForListenerID(EventListenerAcceleration::LISTENER_ID);
        }
        else if (listenerType == EventListener::Type::KEYBOARD)
        {
            removeEventListenersForListenerID(EventListenerKeyboard::LISTENER_ID);
        }
        else
        {
            CCASSERT(false, "Invalid listener type!");
        }
    }

       
    void EventDispatcher::removeCustomEventListeners(const std::string& customEventName)
    {
        removeEventListenersForListenerID(customEventName);
    }

    3.3.3 removeAllEventListeners

      
    void EventDispatcher::removeAllEventListeners()
    {
        bool cleanMap = true;
        std::vector<EventListener::ListenerID> types(_listenerMap.size());
        
        for (const auto& e : _listenerMap)
        {
            if (_internalCustomListenerIDs.find(e.first) != _internalCustomListenerIDs.end())
            {
                cleanMap = false;
            }
            else
            {
                types.push_back(e.first);
            }
        }
    
        for (const auto& type : types)
        {
            removeEventListenersForListenerID(type);
        }
        
        if (!_inDispatch && cleanMap)
        {
            _listenerMap.clear();
        }
    }


    3.4 DispatchEvent(核心内容)

         最终到了核心内容了。为啥我要把核心内容放到后面。假设不看上面,不了解Event。EventListener,EventVector以及Dispatcher是怎样管理EventListener的。看以下的代码就会有非常多的疑惑。

    ok,让我们静静赞赏源代码吧。


        3.4.1 dispatchEvent

        
    void EventDispatcher::dispatchEvent(Event* event)
    {
        if (!_isEnabled)
            return;
        
    	//为dirtyNodesVector中的dirtyNode更新Scene Flag。

    updateDirtyFlagForSceneGraph(); DispatchGuard guard(_inDispatch); //特殊touch事件,转到特殊的touch事件处理 if (event->getType() == Event::Type::TOUCH) { dispatchTouchEvent(static_cast<EventTouch*>(event)); return; } //依据事件的类型。获取事件的ID auto listenerID = __getListenerID(event); //依据事件ID,将该类事件进行排序(先响应谁) sortEventListeners(listenerID); auto iter = _listenerMap.find(listenerID); if (iter != _listenerMap.end()) { auto listeners = iter->second; //该类事件的lambda函数 auto onEvent = [&event](EventListener* listener) -> bool{ //设置event的target event->setCurrentTarget(listener->getAssociatedNode()); //调用响应函数 listener->_onEvent(event); //返回是否已经停止 return event->isStopped(); }; //将该类事件的listeners 和 该类事件的 lambda函数传给该函数 dispatchEventToListeners(listeners, onEvent); } //更新该事件相关的listener updateListeners(event); }


        我们能够看出,特殊的touchEvent和普通的event走的不是同一条控制流程,既然如此,我们就先一般后特殊吧。先来看看一般流程下的DispatchEventToListeners吧

    3.4.2 dispatchEventToListeners


      
    void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
    {
        bool shouldStopPropagation = false;
        auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
        auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
        
    	//总体操作流程分为三个部分,处理优先级<0,=0,>0三个部分
        ssize_t i = 0;
        // priority < 0
        if (fixedPriorityListeners)
        {
            CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");
            
            if (!fixedPriorityListeners->empty())
            {
                for (; i < listeners->getGt0Index(); ++i)
                {
                    auto l = fixedPriorityListeners->at(i);
    				// onEvent(l)的操作调用了event的callBack,而且会返回是否停止,假设停止后,则将shouldStopPropagation标记为true
    				//在其后面的listeners则不会响应到该事件(这里能够看出触摸事件是怎样被吞噬的)
                    if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                    {
                        shouldStopPropagation = true;
                        break;
                    }
                }
            }
        }
        
        if (sceneGraphPriorityListeners)
        {
            if (!shouldStopPropagation)
            {
                // priority == 0, scene graph priority
                for (auto& l : *sceneGraphPriorityListeners)
                {
                    if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                    {
                        shouldStopPropagation = true;
                        break;
                    }
                }
            }
        }
    
        if (fixedPriorityListeners)
        {
            if (!shouldStopPropagation)
            {
                // priority > 0
                ssize_t size = fixedPriorityListeners->size();
                for (; i < size; ++i)
                {
                    auto l = fixedPriorityListeners->at(i);
                    
                    if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                    {
                        shouldStopPropagation = true;
                        break;
                    }
                }
            }
        }
    }
    

    3.4.3 dispatchTouchEvent(3.x版本号的触摸机制)

           
    void EventDispatcher::dispatchTouchEvent(EventTouch* event)
    {
    	//先将EventListeners排序
        sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
        sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
        
        auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
        auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
        
        // If there aren't any touch listeners, return directly.
        if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)
            return;
        
    	//mutableTouches是用来处理allAtOnce的
        bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners);
        
    	//这些touch都来自该事件
        const std::vector<Touch*>& originalTouches = event->getTouches();
        std::vector<Touch*> mutableTouches(originalTouches.size());
        std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin());
    
        //
        // process the target handlers 1st
        //
        if (oneByOneListeners)
        {
            auto mutableTouchesIter = mutableTouches.begin();
            auto touchesIter = originalTouches.begin();
            //遍历touches,每个touch都来自于同一个事件
            for (; touchesIter != originalTouches.end(); ++touchesIter)
            {
                bool isSwallowed = false;
    
    			//事件处理的lambda函数
                auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break
                    EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l);
                    
                    // Skip if the listener was removed.
                    if (!listener->_isRegistered)
                        return false;
                 
                    event->setCurrentTarget(listener->_node);
                    //claimed代表该listener是否接收了该touch(Began返回true or false)
                    bool isClaimed = false;
                    std::vector<Touch*>::iterator removedIter;
                    
    				//依据eventNode的不同,会调用不同的callBack函数
                    EventTouch::EventCode eventCode = event->getEventCode();
                    
                    if (eventCode == EventTouch::EventCode::BEGAN)
                    {
    					//调用began
                        if (listener->onTouchBegan)
                        {
                            isClaimed = listener->onTouchBegan(*touchesIter, event);
                            if (isClaimed && listener->_isRegistered)
                            {
    							//返回true后 将该touch放入该listener的claimedTouches
                                listener->_claimedTouches.push_back(*touchesIter);
                            }
                        }
                    }
    				//假设是后三个move end cancel
                    else if (listener->_claimedTouches.size() > 0
                             && ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
                    {
                        isClaimed = true;
                        //调用对应的callBack
                        switch (eventCode)
                        {
                            case EventTouch::EventCode::MOVED:
                                if (listener->onTouchMoved)
                                {
                                    listener->onTouchMoved(*touchesIter, event);
                                }
                                break;
                            case EventTouch::EventCode::ENDED:
                                if (listener->onTouchEnded)
                                {
                                    listener->onTouchEnded(*touchesIter, event);
                                }
                                if (listener->_isRegistered)
                                {
                                    listener->_claimedTouches.erase(removedIter);
                                }
                                break;
                            case EventTouch::EventCode::CANCELLED:
                                if (listener->onTouchCancelled)
                                {
                                    listener->onTouchCancelled(*touchesIter, event);
                                }
                                if (listener->_isRegistered)
                                {
                                    listener->_claimedTouches.erase(removedIter);
                                }
                                break;
                            default:
                                CCASSERT(false, "The eventcode is invalid.");
                                break;
                        }
                    }
                    
                    // If the event was stopped, return directly.
                    if (event->isStopped())
                    {
                        updateListeners(event);
                        return true;
                    }
                    
                    CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), "");
                    
    				//假设接收该touch而且须要吞噬该touch。会有两个影响
    				//1.Touches(standard 触摸机制)的触摸操作都接收不到该touch了
    				//2.由于返回值是true,在调用dispatchEventToListeners时。在该node之后的node将会不再接收该touch
                    if (isClaimed && listener->_isRegistered && listener->_needSwallow)
                    {
                        if (isNeedsMutableSet)
                        {
                            mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);
                            isSwallowed = true;
                        }
                        return true;
                    }
                    
                    return false;
                };
                
                //结合上面的dispatchEventToListeners的源代码分析。能够看出新版本号的OneByOne touch机制是这种:
    			//1.listener依据Node的优先级排序后。依次响应。

    值得注意的是,新版本号的优先级是依据Node的global Zorder来的。而不是2.x的触摸优先级。

    //2.当TouchEvent Began来了之后,全部的listener会依次影响Touch Began。

    然后再依次响应Touch Move...而不是一个listener响应完 //began move end之后 轮到下一个listener响应的顺序。 //3.吞噬操作仅仅有发生在began return true后才干够发生 dispatchEventToListeners(oneByOneListeners, onTouchEvent); if (event->isStopped()) { return; } if (!isSwallowed) ++mutableTouchesIter; } } // // process standard handlers 2nd // //相比于OneByOne。AllAtOnce要简单很多。值得注意的是被吞噬的touch也不会被AllAtOnce响应到 if (allAtOnceListeners && mutableTouches.size() > 0) { auto onTouchesEvent = [&](EventListener* l) -> bool{ EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l); // Skip if the listener was removed. if (!listener->_isRegistered) return false; event->setCurrentTarget(listener->_node); switch (event->getEventCode()) { case EventTouch::EventCode::BEGAN: if (listener->onTouchesBegan) { listener->onTouchesBegan(mutableTouches, event); } break; case EventTouch::EventCode::MOVED: if (listener->onTouchesMoved) { listener->onTouchesMoved(mutableTouches, event); } break; case EventTouch::EventCode::ENDED: if (listener->onTouchesEnded) { listener->onTouchesEnded(mutableTouches, event); } break; case EventTouch::EventCode::CANCELLED: if (listener->onTouchesCancelled) { listener->onTouchesCancelled(mutableTouches, event); } break; default: CCASSERT(false, "The eventcode is invalid."); break; } // If the event was stopped, return directly. if (event->isStopped()) { updateListeners(event); return true; } return false; }; dispatchEventToListeners(allAtOnceListeners, onTouchesEvent); if (event->isStopped()) { return; } } updateListeners(event); }


          非常多须要注意的地方我全给了中文标识。可是这里我还要再次说明下新版本号的touch OneByOne机制:
          1.listener依据Node的优先级排序后。依次响应。值得注意的是,新版本号的优先级是依据Node的global Zorder来的,而不是2.x的触摸优先级。
           2.当TouchEvent Began来了之后,全部的listener会依次影响Touch Began。然后再依次响应Touch Move...而不是一个listener响应完  began move end之后 轮到下一个listener响应的顺序。
            3.吞噬操作仅仅有发生在began return true后才干够发生

    3.4.4 DispatchCustomEvent (新版本号的NotificationCenter机制)

        
    void EventDispatcher::dispatchCustomEvent(const std::string &eventName, void *optionalUserData)
    {
        EventCustom ev(eventName);
        ev.setUserData(optionalUserData);
        dispatchEvent(&ev);
    }
    

    好简单,这个函数像不像 postNotification(......)?,在3.x的事件中。再也不要使用NotificationCenter了哦~

    4.小结

          Event,EventListener,EventDispatcher的关系
          新的触摸机制
          新的NotificationCenter方法
  • 相关阅读:
    打印沙盒路径
    iOS自定义组与组之间的距离以及视图
    iOS开发之地域选择
    设置按钮文字右对齐
    ios应用下架方法(说明)
    You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgrou
    iOS开发-模拟器的小常识
    iOS-本地的推送
    创建节点学习
    窥探一句话木马后门的背后
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7323383.html
Copyright © 2011-2022 走看看