cocos2d-x 源码分析 : EventDispatcher、EventListener、Event 源码分析 (新触摸机制,新的NotificationCenter机制)【下】

admin 2018-3-27 212


3.4 DispatchEvent(核心内容)

     终于到了核心内容了,为啥我要把核心内容放到后面。如果不看上面,不了解Event,EventListener,EventVector以及Dispatcher是如何管理EventListener的,看下面的代码就会有很多的疑惑。ok,让我们静静欣赏源码吧。

    3.4.1 dispatchEvent

    
  1. void EventDispatcher::dispatchEvent(Event* event)  
  2. {  
  3.     if (!_isEnabled)  
  4.         return;  
  5.       
  6.     //为dirtyNodesVector中的dirtyNode更新Scene Flag。  
  7.     updateDirtyFlagForSceneGraph();  
  8.       
  9.       
  10.     DispatchGuard guard(_inDispatch);  
  11.       
  12.     //特殊touch事件,转到特殊的touch事件处理  
  13.     if (event->getType() == Event::Type::TOUCH)  
  14.     {  
  15.         dispatchTouchEvent(static_cast<EventTouch*>(event));  
  16.         return;  
  17.     }  
  18.       
  19.     //根据事件的类型,获取事件的ID  
  20.     auto listenerID = __getListenerID(event);  
  21.       
  22.     //根据事件ID,将该类事件进行排序(先响应谁)  
  23.     sortEventListeners(listenerID);  
  24.       
  25.     auto iter = _listenerMap.find(listenerID);  
  26.     if (iter != _listenerMap.end())  
  27.     {  
  28.         auto listeners = iter->second;  
  29.         //该类事件的lambda函数  
  30.         auto onEvent = [&event](EventListener* listener) -> bool{  
  31.             //设置event的target  
  32.             event->setCurrentTarget(listener->getAssociatedNode());  
  33.             //调用响应函数  
  34.             listener->_onEvent(event);  
  35.             //返回是否已经停止  
  36.             return event->isStopped();  
  37.         };  
  38.           
  39.         //将该类事件的listeners 和 该类事件的 lambda函数传给该函数  
  40.         dispatchEventToListeners(listeners, onEvent);  
  41.     }  
  42.       
  43.     //更新该事件相关的listener  
  44.     updateListeners(event);  
  45. }  

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

3.4.2 dispatchEventToListeners

  
  1. void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)  
  2. {  
  3.     bool shouldStopPropagation = false;  
  4.     auto fixedPriorityListeners = listeners->getFixedPriorityListeners();  
  5.     auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();  
  6.       
  7.     //整体操作流程分为三个部分,处理优先级<0,=0,>0三个部分  
  8.     ssize_t i = 0;  
  9.     // priority < 0  
  10.     if (fixedPriorityListeners)  
  11.     {  
  12.         CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");  
  13.           
  14.         if (!fixedPriorityListeners->empty())  
  15.         {  
  16.             for (; i < listeners->getGt0Index(); ++i)  
  17.             {  
  18.                 auto l = fixedPriorityListeners->at(i);  
  19.                 // onEvent(l)的操作调用了event的callBack,并且会返回是否停止,如果停止后,则将shouldStopPropagation标记为true  
  20.                 //在其后面的listeners则不会响应到该事件(这里可以看出触摸事件是如何被吞噬的)  
  21.                 if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))  
  22.                 {  
  23.                     shouldStopPropagation = true;  
  24.                     break;  
  25.                 }  
  26.             }  
  27.         }  
  28.     }  
  29.       
  30.     if (sceneGraphPriorityListeners)  
  31.     {  
  32.         if (!shouldStopPropagation)  
  33.         {  
  34.             // priority == 0, scene graph priority  
  35.             for (auto& l : *sceneGraphPriorityListeners)  
  36.             {  
  37.                 if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))  
  38.                 {  
  39.                     shouldStopPropagation = true;  
  40.                     break;  
  41.                 }  
  42.             }  
  43.         }  
  44.     }  
  45.   
  46.     if (fixedPriorityListeners)  
  47.     {  
  48.         if (!shouldStopPropagation)  
  49.         {  
  50.             // priority > 0  
  51.             ssize_t size = fixedPriorityListeners->size();  
  52.             for (; i < size; ++i)  
  53.             {  
  54.                 auto l = fixedPriorityListeners->at(i);  
  55.                   
  56.                 if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))  
  57.                 {  
  58.                     shouldStopPropagation = true;  
  59.                     break;  
  60.                 }  
  61.             }  
  62.         }  
  63.     }  
  64. }  

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

       
  1. void EventDispatcher::dispatchTouchEvent(EventTouch* event)  
  2. {  
  3.     //先将EventListeners排序  
  4.     sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);  
  5.     sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);  
  6.       
  7.     auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);  
  8.     auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);  
  9.       
  10.     // If there aren't any touch listeners, return directly.  
  11.     if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)  
  12.         return;  
  13.       
  14.     //mutableTouches是用来处理allAtOnce的  
  15.     bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners);  
  16.       
  17.     //这些touch都来自该事件  
  18.     const std::vector<Touch*>& originalTouches = event->getTouches();  
  19.     std::vector<Touch*> mutableTouches(originalTouches.size());  
  20.     std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin());  
  21.   
  22.     //  
  23.     // process the target handlers 1st  
  24.     //  
  25.     if (oneByOneListeners)  
  26.     {  
  27.         auto mutableTouchesIter = mutableTouches.begin();  
  28.         auto touchesIter = originalTouches.begin();  
  29.         //遍历touches,每一个touch都来自于同一个事件  
  30.         for (; touchesIter != originalTouches.end(); ++touchesIter)  
  31.         {  
  32.             bool isSwallowed = false;  
  33.   
  34.             //事件处理的lambda函数  
  35.             auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break  
  36.                 EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l);  
  37.                   
  38.                 // Skip if the listener was removed.  
  39.                 if (!listener->_isRegistered)  
  40.                     return false;  
  41.                
  42.                 event->setCurrentTarget(listener->_node);  
  43.                 //claimed代表该listener是否接收了该touch(Began返回true or false)  
  44.                 bool isClaimed = false;  
  45.                 std::vector<Touch*>::iterator removedIter;  
  46.                   
  47.                 //根据eventNode的不同,会调用不同的callBack函数  
  48.                 EventTouch::EventCode eventCode = event->getEventCode();  
  49.                   
  50.                 if (eventCode == EventTouch::EventCode::BEGAN)  
  51.                 {  
  52.                     //调用began  
  53.                     if (listener->onTouchBegan)  
  54.                     {  
  55.                         isClaimed = listener->onTouchBegan(*touchesIter, event);  
  56.                         if (isClaimed && listener->_isRegistered)  
  57.                         {  
  58.                             //返回true后 将该touch放入该listener的claimedTouches  
  59.                             listener->_claimedTouches.push_back(*touchesIter);  
  60.                         }  
  61.                     }  
  62.                 }  
  63.                 //如果是后三个move end cancel  
  64.                 else if (listener->_claimedTouches.size() > 0  
  65.                          && ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))  
  66.                 {  
  67.                     isClaimed = true;  
  68.                     //调用相应的callBack  
  69.                     switch (eventCode)  
  70.                     {  
  71.                         case EventTouch::EventCode::MOVED:  
  72.                             if (listener->onTouchMoved)  
  73.                             {  
  74.                                 listener->onTouchMoved(*touchesIter, event);  
  75.                             }  
  76.                             break;  
  77.                         case EventTouch::EventCode::ENDED:  
  78.                             if (listener->onTouchEnded)  
  79.                             {  
  80.                                 listener->onTouchEnded(*touchesIter, event);  
  81.                             }  
  82.                             if (listener->_isRegistered)  
  83.                             {  
  84.                                 listener->_claimedTouches.erase(removedIter);  
  85.                             }  
  86.                             break;  
  87.                         case EventTouch::EventCode::CANCELLED:  
  88.                             if (listener->onTouchCancelled)  
  89.                             {  
  90.                                 listener->onTouchCancelled(*touchesIter, event);  
  91.                             }  
  92.                             if (listener->_isRegistered)  
  93.                             {  
  94.                                 listener->_claimedTouches.erase(removedIter);  
  95.                             }  
  96.                             break;  
  97.                         default:  
  98.                             CCASSERT(false"The eventcode is invalid.");  
  99.                             break;  
  100.                     }  
  101.                 }  
  102.                   
  103.                 // If the event was stopped, return directly.  
  104.                 if (event->isStopped())  
  105.                 {  
  106.                     updateListeners(event);  
  107.                     return true;  
  108.                 }  
  109.                   
  110.                 CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), "");  
  111.                   
  112.                 //如果接收该touch并且需要吞噬该touch,会有两个影响  
  113.                 //1.Touches(standard 触摸机制)的触摸操作都接收不到该touch了  
  114.                 //2.因为返回值是true,在调用dispatchEventToListeners时,在该node之后的node将会不再接收该touch  
  115.                 if (isClaimed && listener->_isRegistered && listener->_needSwallow)  
  116.                 {  
  117.                     if (isNeedsMutableSet)  
  118.                     {  
  119.                         mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);  
  120.                         isSwallowed = true;  
  121.                     }  
  122.                     return true;  
  123.                 }  
  124.                   
  125.                 return false;  
  126.             };  
  127.               
  128.             //结合上面的dispatchEventToListeners的源码分析,可以看出新版本的OneByOne touch机制是这样的:  
  129.             //1.listener根据Node的优先级排序后,依次响应。值得注意的是,新版本的优先级是根据Node的global Zorder来的,而不是2.x的触摸优先级。  
  130.             //2.当TouchEvent Began来了之后,所有的listener会依次影响Touch Began。然后再依次响应Touch Move...而不是一个listener响应完  
  131.             //began move end之后 轮到下一个listener响应的顺序。  
  132.             //3.吞噬操作只有发生在began return true后才可以发生  
  133.             dispatchEventToListeners(oneByOneListeners, onTouchEvent);  
  134.             if (event->isStopped())  
  135.             {  
  136.                 return;  
  137.             }  
  138.               
  139.             if (!isSwallowed)  
  140.                 ++mutableTouchesIter;  
  141.         }  
  142.     }  
  143.       
  144.     //  
  145.     // process standard handlers 2nd  
  146.     //  
  147.     //相比于OneByOne,AllAtOnce要简单许多。值得注意的是被吞噬的touch也不会被AllAtOnce响应到  
  148.     if (allAtOnceListeners && mutableTouches.size() > 0)  
  149.     {  
  150.           
  151.         auto onTouchesEvent = [&](EventListener* l) -> bool{  
  152.             EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l);  
  153.             // Skip if the listener was removed.  
  154.             if (!listener->_isRegistered)  
  155.                 return false;  
  156.               
  157.             event->setCurrentTarget(listener->_node);  
  158.               
  159.             switch (event->getEventCode())  
  160.             {  
  161.                 case EventTouch::EventCode::BEGAN:  
  162.                     if (listener->onTouchesBegan)  
  163.                     {  
  164.                         listener->onTouchesBegan(mutableTouches, event);  
  165.                     }  
  166.                     break;  
  167.                 case EventTouch::EventCode::MOVED:  
  168.                     if (listener->onTouchesMoved)  
  169.                     {  
  170.                         listener->onTouchesMoved(mutableTouches, event);  
  171.                     }  
  172.                     break;  
  173.                 case EventTouch::EventCode::ENDED:  
  174.                     if (listener->onTouchesEnded)  
  175.                     {  
  176.                         listener->onTouchesEnded(mutableTouches, event);  
  177.                     }  
  178.                     break;  
  179.                 case EventTouch::EventCode::CANCELLED:  
  180.                     if (listener->onTouchesCancelled)  
  181.                     {  
  182.                         listener->onTouchesCancelled(mutableTouches, event);  
  183.                     }  
  184.                     break;  
  185.                 default:  
  186.                     CCASSERT(false"The eventcode is invalid.");  
  187.                     break;  
  188.             }  
  189.               
  190.             // If the event was stopped, return directly.  
  191.             if (event->isStopped())  
  192.             {  
  193.                 updateListeners(event);  
  194.                 return true;  
  195.             }  
  196.               
  197.             return false;  
  198.         };  
  199.           
  200.         dispatchEventToListeners(allAtOnceListeners, onTouchesEvent);  
  201.         if (event->isStopped())  
  202.         {  
  203.             return;  
  204.         }  
  205.     }  
  206.       
  207.     updateListeners(event);  
  208. }  

      很多需要注意的地方我全给了中文标识,但是这里我还要再次说明下新版本的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机制)

    
  1. void EventDispatcher::dispatchCustomEvent(const std::string &eventName, void *optionalUserData)  
  2. {  
  3.     EventCustom ev(eventName);  
  4.     ev.setUserData(optionalUserData);  
  5.     dispatchEvent(&ev);  
  6. }  

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

4.小结

      Event,EventListener,EventDispatcher的关系
      新的触摸机制
      新的NotificationCenter方法


最新回复 (0)
返回