按照相关资料说法:设置的数值越小,触摸优先级越高,同等优先级,优先响应后添加的
事实从源代码来看:同等优先级时会响应第一个添加的。
例如在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);
}
}
这样之后,就达到了同等优先级,优先响应后添加的