按照相关资料说法:设置的数值越小,触摸优先级越高,同等优先级,优先响应后添加的
事实从源代码来看:同等优先级时会响应第一个添加的。
例如在3.0以前的版本中CCMenu就存在这样的情况,将子节点集合正序遍历改成反序遍历即可修正。
3.0之后触摸模块有改动,统一通过EventDispatcher控制,当然,依然是优先响应先添加的控件,在对集合遍历时时正序遍历,而此时集合为升序排序从小到大 0<,>0,设置的数值越小,触摸优先级越高在这里体现了
源代码如下:
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; // 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); if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l)) { shouldStopPropagation = true; break; } } } } //省略.. }
升序排序代码如下:
void EventDispatcher::sortEventListenersOfFixedPriority(const EventListener::ListenerID& listenerID) { auto listeners = getListeners(listenerID); if (listeners == nullptr) return; auto fixedListeners = listeners->getFixedPriorityListeners(); if (fixedListeners == nullptr) return; // After sort: priority < 0, > 0 std::sort(fixedListeners->begin(), fixedListeners->end(), [](const EventListener* l1, const EventListener* l2) { return l1->getFixedPriority() < l2->getFixedPriority(); }); // FIXME: Should use binary search int index = 0; for (auto& listener : *fixedListeners) { if (listener->getFixedPriority() >= 0) break; ++index; } listeners->setGt0Index(index); #if DUMP_LISTENER_ITEM_PRIORITY_INFO log("-----------------------------------"); for (auto& l : *fixedListeners) { log("listener priority: node (%p), fixed (%d)", l->_node, l->_fixedPriority); } #endif }
到这里,再看同等优先级的问题,在注册添加回调的时候是这样的:
void EventDispatcher::forceAddEventListener(EventListener* listener) { EventListenerVector* listeners = nullptr; EventListener::ListenerID listenerID = listener->getListenerID(); auto itr = _listenerMap.find(listenerID); if (itr == _listenerMap.end()) { listeners = new EventListenerVector(); _listenerMap.insert(std::make_pair(listenerID, listeners)); } else { listeners = itr->second; } listeners->push_back(listener);//添加到容器尾部 if (listener->getFixedPriority() == 0) { setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY); auto node = listener->getAssociatedNode(); CCASSERT(node != nullptr, "Invalid scene graph priority!"); associateNodeAndEventListener(node, listener); if (node->isRunning()) { resumeEventListenersForTarget(node); } } else { setDirty(listenerID, DirtyFlag::FIXED_PRIORITY); } }所以回到上面,对容器做排序,同等优先级是不会交换位置的,所以先添加的还是在前面。然后到派遣事件时,还是先派遣到先添加的。所以现在可以证明 同等优先级时会响应第一个添加的。
那么要改成同等优先级,优先响应后添加可以这样,在将监听添加进容器时插入:
void EventDispatcher::EventListenerVector::push_back(EventListener* listener) { #if CC_NODE_DEBUG_VERIFY_EVENT_LISTENERS CCASSERT(_sceneGraphListeners == nullptr || std::count(_sceneGraphListeners->begin(), _sceneGraphListeners->end(), listener) == 0, "Listener should not be added twice!"); CCASSERT(_fixedListeners == nullptr || std::count(_fixedListeners->begin(), _fixedListeners->end(), listener) == 0, "Listener should not be added twice!"); #endif if (listener->getFixedPriority() == 0) { if (_sceneGraphListeners == nullptr) { _sceneGraphListeners = new std::vector<EventListener*>(); _sceneGraphListeners->reserve(100); } //_sceneGraphListeners->push_back(listener); auto it = _sceneGraphListeners->begin(); for (; it != _sceneGraphListeners->end(); it++) { if ((*it)->getFixedPriority() == listener->getFixedPriority()) break; } _sceneGraphListeners->insert(it, listener); } else { if (_fixedListeners == nullptr) { _fixedListeners = new std::vector<EventListener*>(); _fixedListeners->reserve(100); } //_fixedListeners->push_back(listener); auto it = _fixedListeners->begin(); for (; it != _fixedListeners->end(); it++) { if ((*it)->getFixedPriority() == listener->getFixedPriority()) break; } _fixedListeners->insert(it, listener); } }
这样之后,就达到了同等优先级,优先响应后添加的