Cocos
的事件分发机制,怎么说呢,总感觉有些乱,借此整理一下。先看看与事件分发相关的类。
事件相关的类 Event 相关类, 分发事件的中的事件:
Event
(基类), EventCustom
(自定义事件), EventTouch
(触摸事件), EventMouse
(鼠标事件), EventKeyboard
(键盘事件), EventFocus
(控件获取焦点事件), EventAcceleration
(加速计事件)
事件监听器:
EventListener
, EventListenerCustom
, EventListenerFocus
, EventListenerMouse
, EventListenerTouch
, EventListenerKayboard
, EventListenerAcceleration
事件ID
ListenerID
(事件的区分标志,其实就是std::string
)
事件分发器:
EventDispatcher
(事件分发机制逻辑集合体)
创建事件 创建事件就简单的new
一个Event
的子类即可。
事件监听器的创建与监听 事件监听器,也就是说EventListener
。添加事件监听器有三个方法,都在EventDispatch
中,分别是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void addEventListenerWithSceneGraphPriority (EventListener* listener, Node* node) ;void addEventListenerWithFixedPriority (EventListener* listener, int fixedPriority) ; EventListenerCustom* addCustomEventListener (const std ::string &eventName, const std ::function<void (EventCustom*)>& callback) ;
事件分发的时候主要有两种优先级 。 第一种是:ScenePriority 第二种是:FixedPriority 仔细跳到addEventListenerWithSceneGraphPriority
函数去看看会发现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void EventDispatcher::addEventListenerWithSceneGraphPriority (EventListener* listener, Node* node) { ... listener->setFixedPriority(0 ); ... addEventListener(listener); } EventListenerCustom* EventDispatcher::addCustomEventListener (const std ::string &eventName, const std ::function<void (EventCustom*)>& callback) { EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);\ addEventListenerWithFixedPriority(listener, 1 ); return listener; }
其实事件监听器保存的优先级其实只有 FixPriority 。
从EventListener
这个类的方法中也可以看出来,里面涉及到保存优先级的只有setFixedPriority
这一个函数。
说到优先级,那么事件分发的时候是怎么处理这些优先级的呢?官网只有写 SceneGraphPriority 的优先级是怎么处理的,那么 FixPriority 的优先程度和数值是什么关系,这就去偷窥内部了。 事件分发优先级顺序: 我们来脱掉 EventDispatcher
的衣服看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 void EventDispatcher::dispatchEvent (Event* event) { ... auto listenerID = __getListenerID(event); sortEventListeners(listenerID); auto pfnDispatchEventToListeners = &EventDispatcher::dispatchEventToListeners; if (event->getType() == Event::Type::MOUSE) { pfnDispatchEventToListeners = &EventDispatcher::dispatchTouchEventToListeners; } auto iter = _listenerMap.find(listenerID); if (iter != _listenerMap.end()) { auto listeners = iter->second; auto onEvent = [&event](EventListener* listener) -> bool { event->setCurrentTarget(listener->getAssociatedNode()); listener->_onEvent(event); return event->isStopped(); }; (this ->*pfnDispatchEventToListeners)(listeners, onEvent); } ... }
偷窥代码分析后发现这段代码并没有详细指出分发事件的时候的优先级。仔细想想应该是 sortEventListener
和 pfnDispatchEventToListeners
中在搞鬼。 先分析 sortEventListener
,脱掉她的胖次去里面看看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 void EventDispatcher::sortEventListeners (const EventListener::ListenerID& listenerID) { ... ... if ((int )dirtyFlag & (int )DirtyFlag::FIXED_PRIORITY) { sortEventListenersOfFixedPriority(listenerID); } if ((int )dirtyFlag & (int )DirtyFlag::SCENE_GRAPH_PRIORITY) { auto rootNode = Director::getInstance()->getRunningScene(); if (rootNode) { sortEventListenersOfSceneGraphPriority(listenerID, rootNode); } ... } } } void EventDispatcher::sortEventListenersOfFixedPriority (const EventListener::ListenerID& listenerID) { auto listeners = getListeners(listenerID); ... std ::sort(fixedListeners->begin(), fixedListeners->end(), [](const EventListener* l1, const EventListener* l2) { return l1->getFixedPriority() < l2->getFixedPriority(); }); ... } void EventDispatcher::sortEventListenersOfSceneGraphPriority (const EventListener::ListenerID& listenerID, Node* rootNode) { auto listeners = getListeners(listenerID); ... auto sceneGraphListeners = listeners->getSceneGraphPriorityListeners(); ... _nodePriorityIndex = 0 ; _nodePriorityMap.clear(); visitTarget(rootNode, true ); std ::sort(sceneGraphListeners->begin(), sceneGraphListeners->end(), [this ](const EventListener* l1, const EventListener* l2) { return _nodePriorityMap[l1->getAssociatedNode()] > _nodePriorityMap[l2->getAssociatedNode()]; }); ... }
上面写了两种优先级的排序,一种是 FixPriority ,优先级根据 fixedPriority 的数值从小往大排序、另一种是 SceneGraphPriority ,根据节点在渲染树种的优先级排序,具体怎么样官网有解释,这里不做展开。
值的注意的是 sortEventListener
的时候,判断当前 ListenerID
的类型是用位标记来判断的,一个 int
类型的 flag。也就是说明一个 listenerID
既可以是 SceneGraphPriority 也可以是 FixedPriority ,那么实际分发的时候这两个的优先级怎么排?答案就在 pfnDispatchEventToListeners
中 pfnDispatchEventToListeners
可以指向两个方法:dispatchEventToListeners
和 dispatchTouchEventToListeners
。其中两个方法除了分发SceneGraphPriority
的时候不一样外,其他的一样,为了方便起见,这里只分析 dispatchEventToListeners
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 void EventDispatcher::dispatchEventToListeners (EventListenerVector* listeners, const std ::function<bool (EventListener*)>& onEvent) { bool shouldStopPropagation = false ; auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); ssize_t i = 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); if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l)) { shouldStopPropagation = true ; break ; } } } } if (sceneGraphPriorityListeners) { if (!shouldStopPropagation) { for (auto & l : *sceneGraphPriorityListeners) { if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l)) { shouldStopPropagation = true ; break ; } } } } if (fixedPriorityListeners) { if (!shouldStopPropagation) { 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 ; } } } } }
这里面清楚的写出了事件分发时候的逻辑处理,先分发事件到 *fixedPriority < 0* 的监听器中,然后再分发到 = 0 的监听器(*SceneGraphPriority*)中,最后在分发到 > 0 的监听器中,如果中途出现 onEvent
返回为 true
的结果,则终止分发。
Ps:这里的 onEvent
调用的其实就是上面 dispatchEvent
代码中的 lambda 表达式。如果想要创建一个触摸事件的优先级比当前所有的触摸事件优先级都高话,只需要把 fixedPriority 的数值设为 < 0 即可。