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后才可以发生
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方法
最新回复 (0)