EventDispatcher:
一、成员变量:
protected:
enum class DirtyFlag // 事件监听器容器的脏标志。容器中新增或移除事件监听器时设置。
{
NONE = 0, // 清空脏标志时使用。
FIXED_PRIORITY = 1 << 0, // 存储固定优先级事件监听器的容器的脏标志。
SCENE_GRAPH_PRIORITY = 1 << 1, // 存储场景图优先级事件监听器的容器的脏标志。
ALL = FIXED_PRIORITY | SCENE_GRAPH_PRIORITY
};
/* 事件监听器ID与存储此类所有事件监听器的EventListenerVector类之间的映射。
* 例如,场景图优先级的鼠标按下事件监听器、固定优先级的鼠标移动事件监听器、场景图优先级的鼠标移动事件监听器、…… 都存储在EventListenerVector中。
* 鼠标事件监听器ID“__cc_mouse”对应自己的EventListenerVector。
*/
std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;
/* ListenerID <--> EventListenerVector DirtyFlag
* ├── _fixedListeners <--> FIXED_PRIORITY ──┤
* └── _sceneGraphListeners <--> SCENE_GRAPH_PRIORITY ──┘
* 如上图,ListenerID通过EventListenerVector与DirtyFlag对应起来,
-
我觉得应在EventListenerVector中创建一个DirtyFlag类型的变量。
- DirtyFlag本来就与EventListenerVector中的两个容器有一一对应关系,这样单拎出来做个映射,感觉很怪。
*/
std::unordered_map<EventListener::ListenerID, DirtyFlag> _priorityDirtyFlagMap;
/* 与节点所绑定的所有场景图优先级的事件监听器与该节点之间的映射。
- 只有场景图优先级的事件监听器才有此映射,因为固定优先级的事件监听器没有绑定节点。
- 例如,由一张图片创建的精灵绑定了鼠标按下场景图优先级事件监听器、键盘按下场景图优先级事件监听器、…… 这些事件监听器都存储在std::vector<EventListener*>中。
- 由这张图片创建的精灵对应自己的std::vector<EventListener*>。
/
std::unordered_map<Node, std::vector<EventListener*>*> _nodeListenersMap;
/* 节点与其优先级的映射。
- 节点的优先级最终决定了与节点绑定的场景图优先级事件监听器的优先级。
- Node*不定义成vector<Node *>,我想是为了滤重,两个事件不能有相同的优先级。
/
std::unordered_map<Node, int> _nodePriorityMap;
/* 节点与其ZOrder的映射。
- 例如,节点①的ZOrder为1、节点②的ZOrder为-5、节点③的Zorder为1,
- 那么一共有两个映射,第一个是-5 <–> {节点②},第二个是1 <–> {节点①, 节点③}。
/
std::unordered_map<float, std::vector<Node>> _globalZOrderNodeMap;
std::vector<EventListener*> _toAddedListeners; // 存放由于事件分发器正在分发事件而无法被注册的事件监听器(当前事件被分发完成之后被注册)。
std::set<Node*> _dirtyNodes; // 绑定的(场景图优先级)事件监听器有变化的节点。
int _inDispatch; // 正在分发的事件数量。
bool _isEnabled; // 事件分发器是否可用。
int _nodePriorityIndex; // 场景图优先级事件监听器所绑定的节点的优先级计数器。
std::setstd::string _internalCustomListenerIDs; // 存储内部事件监听器ID。friend class Node;
- DirtyFlag本来就与EventListenerVector中的两个容器有一一对应关系,这样单拎出来做个映射,感觉很怪。
二、成员方法:
其中一些get/set方法不一一列举。
(1) EventDispatcher();
~EventDispatcher();
实现源码:
EventDispatcher::EventDispatcher()
: _inDispatch(0)
, _isEnabled(false)
, _nodePriorityIndex(0)
{
_toAddedListeners.reserve(50); // 最多可存放50个待放入事件分发器中的事件监听器。
// 以下事件监听器ID供内部使用,这样能够保证在调用removeAllEventListeners()时,这些事件监听器不被移除。
_internalCustomListenerIDs.insert(EVENT_COME_TO_FOREGROUND); // 程序切换到前台。
_internalCustomListenerIDs.insert(EVENT_COME_TO_BACKGROUND); // 程序切换到后台。
_internalCustomListenerIDs.insert(EVENT_RENDERER_RECREATED); // 程序重新渲染。
}
EventDispatcher::~EventDispatcher()
{
_internalCustomListenerIDs.clear(); // 移除内部事件监听器。
removeAllEventListeners(); // 移除所有非内部事件监听器。
}
(2) void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);
添加一个场景图优先级的事件监听器。
void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);
添加一个固定优先级的事件监听器。
EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);
添加一个自定义优先级的事件监听器。
listener:待添加的事件监听器。
node:与事件监听器绑定的节点。
fixedPriority:指定的事件监听器的优先级。
eventName:自定义事件监听器的ID(这个变量名起的不好,肯定是沿用了EventCustom的变量名,*_*)。
callback:自定义事件的回调函数。
实现源码:
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
CCASSERT(listener && node, “Invalid parameters.”);
CCASSERT(!listener->isRegistered(), “The listener has been registered.”); // 已注册过的事件监听器不能被再次注册。
if (!listener->checkAvailable()) // 多态,调用的具体事件监听器的checkAvailable(),检查事件监听器是否可用。
return;
listener->setAssociatedNode(node);
// 将事件监听器与节点绑定。根据绑定节点的ZOrder决定场景图优先级事件监听器的优先级。
listener->setFixedPriority(0);
// 场景图优先级的事件监听器的优先级固定为0。
listener->setRegistered(true);
// 为什么事件监听器还没有被放入事件分发器中就已经被设置成“已注册”状态?
addEventListener(listener); // 注册事件监听器。
}
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
CCASSERT(listener, “Invalid parameters.”);
CCASSERT(!listener->isRegistered(), “The listener has been registered.”);
// 只有场景图优先级的事件监听器的优先级才能被设置为0。
CCASSERT(fixedPriority != 0, “0 priority is forbidden for fixed priority since it’s used for scene graph based priority.”);
if (!listener->checkAvailable())
return;
listener->setAssociatedNode(nullptr);
// 固定优先级的事件监听器不绑定节点。根据设定的优先级决定固定优先级事件监听器的优先级。
listener->setFixedPriority(fixedPriority);
// 固定优先级的事件监听器的优先级需要用户指定一个非0整数。
listener->setRegistered(true);
// 为什么事件监听器还没有被放入事件分发器中就已经被设置成“已注册”状态?
listener->setPaused(false);
// 固定优先级的事件监听器不会处于暂停状态。为什么这么设定?
addEventListener(listener); // 注册事件监听器。
}
EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)
{
EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);
addEventListenerWithFixedPriority(listener, 1);
// 实际注册了一个优先级为1的固定优先级的事件监听器。为什么这么设定?
return listener;
// 这里返回创建的事件监听器是为了让用户能够移除自己创建的自定义事件监听器,EventDispatcher::removeAllEventListeners()不会移除这些自定义事件监听器。为什么不用个容器保存这些自定义事件监听器,然后在EventDispatcher::removeAllEventListeners()的时候一起移除。
}
(3) void addEventListener(EventListener* listener);
向事件分发器注册事件监听器,如果事件分发器正在分发事件,则注册延迟到当前事件分发之后进行。
void forceAddEventListener(EventListener* listener);
向事件分发器注册事件监听器,无论事件分发器是否在分发事件,强制注册。
listener:待注册的事件监听器。
实现源码:
void EventDispatcher::addEventListener(EventListener* listener)
{
if (_inDispatch == 0) // 如果事件分发器没有在分发事件(分发事件的数量为0)。
{
forceAddEventListener(listener); // 真正放心大胆的注册事件监听器。
}
else // 如果有事件正在分发。
{
_toAddedListeners.push_back(listener); // 将事件监听器放入_toAddedListeners容器中,等待当前事件分发完成后updateListeners()的过程中再注册。
}
listener->retain(); // 事件监听器正在被事件分发器使用,保留引用计数。
}
void EventDispatcher::forceAddEventListener(EventListener* listener)
{
EventListenerVector* listeners = nullptr;
EventListener::ListenerID listenerID = listener->getListenerID(); // 获得事件监听器ID。
auto itr = _listenerMap.find(listenerID); // 在_listenerMap寻找此ID的映射。
if (itr == _listenerMap.end()) // 如果没找到,说明之前没有注册过这类事件监听器。
{
listeners = new (std::nothrow) EventListenerVector(); // 创建存储此类事件监听器的EventListenerVector类。
_listenerMap.insert(std::make_pair(listenerID, listeners)); // 创建此类事件监听器ID与此类事件监听器EventListenerVector类之间的映射。
}
else // 如果找到了,说明之前注册过这类事件监听器。
{
listeners = itr->second; // 获取存储此类事件监听器的EventListenerVector类。
}
listeners->push_back(listener); // 将事件监听器存入EventListenerVector类中。
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); // 固定优先级事件监听器的容器中新增了元素,设置脏标志。
}
}
关键点总结:
1、这里的函数名字起的容易让人误解函数真正的用途(起码我刚开始看的时候是误解了,-_-)。
addEventListener()是个外壳,它的功能在于安排合理的时间注册事件监听器。
而forceAddEventListener()是真正注册事件监听器的函数,它也没有什么强制不强制之说,因为合理的时间已经被其他函数安排好了。
(4) void setDirty(const EventListener::ListenerID& listenerID, DirtyFlag flag);
设置事件监听器容器的脏标志。
void setDirtyForNode(Node* node);
设置节点的脏标志(该节点所绑定的事件监听器有变化)。
listenerID:事件监听器ID。
flag:待设置的脏标志。
实现源码:
void EventDispatcher::setDirty(const EventListener::ListenerID& listenerID, DirtyFlag flag)
{
auto iter = _priorityDirtyFlagMap.find(listenerID); // 在_priorityDirtyFlagMap中找listenerID的映射。
if (iter == _priorityDirtyFlagMap.end()) // 没有找到。
{
_priorityDirtyFlagMap.insert(std::make_pair(listenerID, flag)); // 存储映射listenerID <–> DirtyFlag。
}
else // 找到了。
{
// 更新listenerID已有的DirtyFlag。
int ret = (int)flag | (int)iter->second;
iter->second = (DirtyFlag) ret;
}
}
void EventDispatcher::setDirtyForNode(Node* node)
{
if (_nodeListenersMap.find(node) != _nodeListenersMap.end()) // 如果在_nodeListenersMap中找的到node的映射。
{
_dirtyNodes.insert(node); // 设置node的脏标志。
}
// 对node的子节点做同样的操作。
const auto& children = node->getChildren();
for (const auto& child : children)
{
setDirtyForNode(child);
}
}
(5) void associateNodeAndEventListener(Node* node, EventListener* listener);
存储节点与事件监听器的映射(只有场景图优先级的事件监听器才会用到)。
void dissociateNodeAndEventListener(Node* node, EventListener* listener);
从与node绑定的(场景图优先级)事件监听器容器中移除指定的(场景图优先级)事件监听器。
node:节点。
listener:(场景图优先级)事件监听器。
实现源码:
void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener)
{
std::vector<EventListener*>* listeners = nullptr;
auto found = _nodeListenersMap.find(node); // 在_nodeListenersMap中找node的映射。
if (found != _nodeListenersMap.end()) // 如果找到了。
{
listeners = found->second; // 获得与node绑定的(场景图优先级)事件监听器容器。
}
else // 没找到。
{
listeners = new std::vector<EventListener*>(); // 创建将与node绑定的(场景图优先级)事件监听器容器。
_nodeListenersMap.insert(std::make_pair(node, listeners)); // 存储映射node <–> std::vector<EventListener*>。
}
listeners->push_back(listener); // 将事件监听器放入该node所对应的std::vector<EventListener*>中。
}
void EventDispatcher::dissociateNodeAndEventListener(Node* node, EventListener* listener)
{
std::vector<EventListener*>* listeners = nullptr;
auto found = _nodeListenersMap.find(node); // 在_nodeListenersMap中找node的映射。
if (found != _nodeListenersMap.end()) // 如果找到了。
{
listeners = found->second; // 获得与node绑定的(场景图优先级)事件监听器容器。
auto iter = std::find(listeners->begin(), listeners->end(), listener); // 在容器中寻找待解除绑定的(场景图优先级)事件监听器。
if (iter != listeners->end()) // 如果找到了。
{
listeners->erase(iter); // 从容器中移除指定的(场景图优先级)事件监听器。
}
if (listeners->empty()) // 如果容器已经空了。
{
_nodeListenersMap.erase(found); // 从_nodeListenersMap中移除该node的映射。
delete listeners; // 删除容器。
}
}
}
(6) void resumeEventListenersForTarget(Node* target, bool recursive = false);
设置所有与节点绑定的(场景图优先级)事件监听器为非暂停状态。
void pauseEventListenersForTarget(Node* target, bool recursive = false);
设置所有与节点绑定的(场景图优先级)事件监听器为暂停状态。
target:节点。
recursive:是否对子节点递归的进行相同的处理。
实现源码:
void EventDispatcher::resumeEventListenersForTarget(Node* target, bool recursive/* = false */)
{
auto listenerIter = _nodeListenersMap.find(target); // 在_nodeListenersMap中找node的映射。
if (listenerIter != _nodeListenersMap.end()) // 如果找到了。
{
auto listeners = listenerIter->second; // 获得与node绑定的(场景图优先级)事件监听器容器。
for (auto& l : *listeners) // 取出容器中每一个事件监听器。
{
l->setPaused(false); // 这里就是将与节点绑定的所有的(场景图优先级)事件监听器设置为非暂停状态。
}
}
// _toAddedListeners中有与该节点绑定的(场景图优先级)事件监听器也要做同样的设置。
for (auto& listener : _toAddedListeners)
{
if (listener->getAssociatedNode() == target) // 一定要是该节点的,其他节点不管。
{
listener->setPaused(false);
}
}
// 这里之后会在分发事件的过程中通过node找到所有与其绑定的事件监听器,然后设置这些事件监听器的脏标志,为什么不直接设置事件监听器所在容器的脏标志?
setDirtyForNode(target); // 将该节点设置为脏节点(该节点所对应的事件监听器有变化)。
if (recursive) // 是否递归的对子节点做同样的操作。
{
// 获取子节点并对其做同样的操作。
const auto& children = target->getChildren();
for (const auto& child : children)
{
resumeEventListenersForTarget(child, true);
}
}
}
void EventDispatcher::pauseEventListenersForTarget(Node* target, bool recursive/* = false */)
{
auto listenerIter = _nodeListenersMap.find(target);
if (listenerIter != _nodeListenersMap.end())
{
auto listeners = listenerIter->second;
for (auto& l : *listeners)
{
l->setPaused(true);
}
}
for (auto& listener : _toAddedListeners)
{
if (listener->getAssociatedNode() == target)
{
listener->setPaused(true);
}
}
// 注意这里就没有将节点设置脏节点。为什么?
if (recursive)
{
const auto& children = target->getChildren();
for (const auto& child : children)
{
pauseEventListenersForTarget(child, true);
}
}
}
关键点总结:
1、一个设置节点为脏节点,另一个不设置的原因?
(7) void dispatchEvent(Event* event);
分发事件。
void dispatchCustomEvent(const std::string &eventName, void *optionalUserData = nullptr);
分发用户自定义事件。
void dispatchTouchEvent(EventTouch* event);
分发触摸事件。
void dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent);
分发事件给事件监听器。
event:待分发的事件。
eventName:待分发的用户自定义事件名称。
optionalUserData:用户数据。
listeners:待接收事件的事件监听器。
onEvent:执行分发事件操作的匿名函数。
实现源码:
void EventDispatcher::dispatchEvent(Event* event)
{
if (!_isEnabled) // 分发器是否可用。
return;
updateDirtyFlagForSceneGraph(); // 设置与_dirtyNodes中脏节点绑定的事件监听器所在的EventListenerVector中存放场景图优先级事件监听器容器的脏标志。
DispatchGuard guard(_inDispatch); // 当前正在分发的事件数量+1。
if (event->getType() == Event::Type::TOUCH) // 如果是触摸事件,有单独的函数进行处理(Event::Type::TOUCH中包含着单点触摸ALL_AT_ONCE和多点触摸ONE_BY_NONE)。
{
dispatchTouchEvent(static_cast<EventTouch*>(event));
return;
}
auto listenerID = __getListenerID(event); // 获取事件所对应的事件监听器ID。
sortEventListeners(listenerID); // 将listenerID所对应的EventListenerVector中两个存储事件监听器的容器中的元素分别按照各自的规则以优先级从高到低的顺序排序。
auto iter = _listenerMap.find(listenerID); // 在_listenerMap寻找此ID的映射。
if (iter != _listenerMap.end()) // 如果找到了。
{
auto listeners = iter->second; // 获取此listenerID所对应的EventListenerVector。
auto onEvent = &event](EventListener* listener) -> bool{ // 分发事件的匿名函数。
event->setCurrentTarget(listener->getAssociatedNode()); // 设置事件监听器绑定的节点(触发事件的节点)。
listener->_onEvent(event);
// 调用事件监听器回调函数(注意!这里就是用户所提供的事件回调函数)。
return event->isStopped(); // 事件是否已停止。
};
dispatchEventToListeners(listeners, onEvent); // 分发事件给事件监听器。
}
updateListeners(event); // 更新事件监听器。
// 这里注意,上面的guard会在这里系构,即当前正在分发的事件数量-1。
}
void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
// 将listenerID所对应的EventListenerVector中两个存储事件监听器的容器中的元素分别按照各自的规则以优先级从高到低的顺序排序。
sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
// 获取listenerID对应的EventListenerVector。
auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
// 如果没有注册任何一种触摸事件的事件监听器,则直接返回。
if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)
return;
bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners); // 是否既注册了处理单点触摸的事件监听器,同时又注册了处理多点触摸的事件监听器。
const std::vector<Touch*>& originalTouches = event->getTouches(); // 获取同时触摸的所有点的信息。
/* 将所有触摸点的信息拷贝一份放到mutableTouches容器中。
-
这里不明白为什么要用这第二个容器,我觉得一个容器即可。见关键点总结第二条。
/
std::vector<Touch> mutableTouches(originalTouches.size());
std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin());if (oneByOneListeners) // 如果注册了单点触摸事件监听器,事件首先传递给单点触摸事件监听器。
{
auto mutableTouchesIter = mutableTouches.begin();
auto touchesIter = originalTouches.begin();for (; touchesIter != originalTouches.end(); ++touchesIter) // 依次遍历originalTouches中每一个触摸点的信息。 { bool isSwallowed = false; // 是否向多点触摸事件监听器传递该触摸点的信息,初始为否。 auto onTouchEvent = &](EventListener* l) -> bool { // 处理单点触摸事件的匿名函数。 EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l); // 转换为子类的类型,EventListener --> EventListenerTouchOneByOne。 // 如果事件监听器在分发事件的这个过程中被remove,则返回失败。 if (!listener->_isRegistered) return false; event->setCurrentTarget(listener->_node); // 设置事件监听器绑定的节点(触发事件的节点)。 bool isClaimed = false; // 这个变量代表当前这个触摸点是否已经被成功的处理完成,初始状态为false。 std::vector<Touch*>::iterator removedIter; EventTouch::EventCode eventCode = event->getEventCode(); // 获取触摸事件类型。 if (eventCode == EventTouch::EventCode::BEGAN) // 如果是触摸开始事件。 { if (listener->onTouchBegan) // 如果用户提供了OneByOne模式触摸开始事件的回调函数。 {
isClaimed = listener->onTouchBegan(touchesIter, event); // 调用事件监听器回调函数(注意!这里就是用户所提供的事件回调函数)。
if (isClaimed && listener->_isRegistered) // 如果此触摸点被成功的处理完成,并且事件监听器还处于注册状态。
{
/ 将此触摸点信息放入_claimedTouches中。
* 用户的触摸动作还并没有完成,之后要继续处理MOVED、ENDED或者CANCELLED。之后的这些动作要在_claimedTouches中查找,确认是否有与自己对应的BEGIN。
*/
listener->_claimedTouches.push_back(*touchesIter);
}
}
}
else if (listener->_claimedTouches.size() > 0 // 如果是其他触摸事件,并且此事件的触摸点信息在_claimedTouches中能找到(此触摸点的BEGAN事件成功处理完成)。
&& ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
{
isClaimed = true; // 此触摸点被成功的处理完成。
// 根据触摸事件类型,调用对应的回调函数(用户提供的)。
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); // 用户的整个触摸动作完成,此触摸点的信息从_claimedTouches中移除。
}
break;
case EventTouch::EventCode::CANCELLED:
// 与ENDED事件有什么区别?什么时候会触发?
if (listener->onTouchCancelled)
{
listener->onTouchCancelled(*touchesIter, event);
}
if (listener->_isRegistered)
{
listener->_claimedTouches.erase(removedIter); // 用户的整个触摸动作完成,此触摸点的信息从_claimedTouches中移除。
}
break;
default:
CCASSERT(false, “The eventcode is invalid.”);
break;
}
}
if (event->isStopped()) // 如果触摸事件已停止。
{
updateListeners(event); // 更新事件监听器。
return true; // 返回触摸事件已停止。
}
CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), "");
// 如果此触摸点被成功的处理完成,并且事件监听器处于已注册状态,并且事件监听器需要吞噬事件(通过EventListenerTouchOneByOne::setSwallowTouches()设置的)。
if (isClaimed && listener->_isRegistered && listener->_needSwallow)
{
if (isNeedsMutableSet) // 如果既注册了处理单点触摸的事件监听器,同时又注册了处理多点触摸的事件监听器。
{
mutableTouchesIter = mutableTouches.erase(mutableTouchesIter); // 则删除此触摸点的信息,保证多点触摸事件监听器不会看到此触摸点的信息(即事件不向多点触摸事件监听器传递)。
isSwallowed = true; // 不再向多点触摸事件监听器传递该触摸点的信息。
}
return true; // 返回触摸事件已停止。
}
return false; // 返回触摸事件未停止。
};
dispatchEventToListeners(oneByOneListeners, onTouchEvent); // 分发事件给事件监听器。
if (event->isStopped()) // 如果触摸事件已停止。
{
return;
}
/* 如果向多点触摸事件监听器传递该触摸点的信息,则mutableTouches容器中保留了此触摸点的信息,所以mutableTouchesIter要向后移动。
* 如果不向多点触摸事件监听器传递该触摸点的信息,则mutableTouches容器中删除了此触摸点的信息,所以mutableTouchesIter保持不动。
*/
if (!isSwallowed)
++mutableTouchesIter;
}
}
if (allAtOnceListeners && mutableTouches.size() > 0) // 如果注册了多点触摸事件监听器,并且有触摸点要处理。
{
auto onTouchesEvent = &](EventListener* l) -> bool{ // 处理多点触摸事件的匿名函数。
EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l); // 转换为子类的类型,EventListener --> EventListenerTouchAllAtOnce。
// 如果事件监听器在分发事件的这个过程中被remove,则返回失败。
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); // 更新事件监听器。
}
void EventDispatcher::dispatchCustomEvent(const std::string &eventName, void *optionalUserData)
{
EventCustom ev(eventName); // 创建用户自定义事件类。
ev.setUserData(optionalUserData); // 设置用户数据。
dispatchEvent(&ev); // 分发用户自定义事件。
}
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) // 先分发给小于零的固定优先级事件监听器。
{
// 第一个优先级>=0的事件监听器的索引不能越界。
CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");
/* 这里判空没意义吧。
* 因为如果容器为空,listeners->getGt0Index()还大于0(这个值不会被设置为小于0),上面的断言过不去。
* 而如果容器为空,listeners->getGt0Index()等于0,下面的for()进不去。
*/
if (!fixedPriorityListeners->empty())
{
for (; i < listeners->getGt0Index(); ++i) // 上面i = 0,从容器中第一个事件监听器开始分发。
{
auto l = fixedPriorityListeners->at(i); // 获取容器中的事件监听器。
// 如果事件监听器可用,并且非暂停,并且已注册,则向事件监听器分发事件,最后onEvent()在分发事件完成后返回事件是否已停止。
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) // 从容器中第一个事件监听器开始分发。
{
// 如果事件监听器可用,并且非暂停,并且已注册,则向事件监听器分发事件,最后onEvent()在分发事件完成后返回事件是否已停止。
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) // 这里i从上面的值开始,也就是固定事件监听器容器中第一个优先级大于等于0的事件监听器。
{
auto l = fixedPriorityListeners->at(i); // 获取容器中的事件监听器。
// 如果事件监听器可用,并且非暂停,并且已注册,则向事件监听器分发事件,最后onEvent()在分发事件完成后返回事件是否已停止。
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
// 固定优先级的事件监听器永不会处于暂停状态,那么这里的暂停判断就多余了。
{
shouldStopPropagation = true; // 事件已停止,不要将事件再分发给优先级更低的事件监听器。
break;
}
}
}
}
}
关键点总结:
1、触摸事件首先传递给单点触摸事件监听器,等待单点触摸事件监听器处理完成,如果其允许事件继续向下传递(单点触摸事件监听器不吞噬事件),则事件才会传递给多点触摸事件监听器处理。
2、EventDispatcher::dispatchTouchEvent中,不明白为什么要用originalTouches和mutableTouches两个容器。
从源码中看起来originalTouches给oneByOne事件使用,而mutableTouches给allAtOnce事件使用。oneByOne吞噬的触摸点要在mutableTouches中删除,这样allAtOnce事件就看不到了。
我觉得要实现这个效果,一个容器即可。mutableTouches都换成originalTouches,mutableTouchesIter都换成touchesIter,for()中最后的++touchesIter去掉,让其在if (!isSwallowed)判断中++即可。
3、当同一时间按了多个点时,一个事件将这些点全部携带过来。OneByOne的意思就是将这些点一个一个传给我,我要一个一个处理;而AllAtOnce的意思是将这些点全部一起传给我,我要一起处理。
(8) void updateDirtyFlagForSceneGraph();
处理_dirtyNodes中的所有脏节点。
void updateListeners(Event* event);
移除所有被标记为“移除”(移除监听器的相关函数标记的)的事件监听器;删除_listenerMap中已经没有用处的映射;注册所有由于事件分发而未注册完成的事件监听器。
event:正在分发的事件。
实现源码:
void EventDispatcher::updateDirtyFlagForSceneGraph()
{
if (!_dirtyNodes.empty()) // 如果_dirtyNodes中有脏节点。
{
for (auto& node : _dirtyNodes) // 遍历每一个脏节点。
{
auto iter = _nodeListenersMap.find(node); // 在_nodeListenersMap中找该脏节点的映射。
if (iter != _nodeListenersMap.end()) // 如果找到了。
{
for (auto& l : *iter->second) // 获得与node绑定的(场景图优先级)事件监听器容器中的每个(场景图优先级)事件监听器。
{
setDirty(l->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY); // 设置该(场景图优先级)事件监听器所在EventListenerVector中存放场景图优先级事件监听器容器的脏标志。
}
}
}
_dirtyNodes.clear(); // 清空已经处理过的脏节点。
}
}
void EventDispatcher::updateListeners(Event* event)
{
CCASSERT(_inDispatch > 0, “If program goes here, there should be event in dispatch.”); // 该函数是在分发事件的过程结尾处调用的,所以如果程序走到这里,一定有事件正在分发。
auto onUpdateListeners = (const EventListener::ListenerID& listenerID) // 移除被标记为“移除”的事件监听器的匿名函数。
{
auto listenersIter = _listenerMap.find(listenerID); // 在_listenerMap寻找此ID的映射。
if (listenersIter == _listenerMap.end()) // 如果没找到,直接返回。
return;
auto listeners = listenersIter->second; // 获取此listenerID所对应的EventListenerVector。
auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); // 获取存储固定优先级事件监听器的容器。
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); // 获取存储场景图优先级事件监听器的容器。
// 从容器中移除没有注册的场景图优先级事件监听器(移除监听器的相关函数中会将事件监听器注销)。
if (sceneGraphPriorityListeners) // 如果容器存在。
{
// 不在for()中++的意义在于没有注册的事件监听器会被erase(),之后的事件监听器向前平移,此时索引不能++。
for (auto iter = sceneGraphPriorityListeners->begin(); iter != sceneGraphPriorityListeners->end();)
{
auto l = *iter;
if (!l->isRegistered()) // 如果事件监听器没有注册。
{
iter = sceneGraphPriorityListeners->erase(iter); // 从容器中移除此事件监听器。
l->release(); // 此事件监听器减少引用计数。
}
else
{
++iter;
}
}
}
// 从容器中移除没有注册的固定优先级事件监听器(移除监听器的相关函数中会将事件监听器注销)。
if (fixedPriorityListeners) // 如果容器存在。
{
for (auto iter = fixedPriorityListeners->begin(); iter != fixedPriorityListeners->end();)
{
auto l = *iter; // iter是容器中数据的地址(&(EventListener*)),这里需要获得容器中的具体元素(EventListener*)。
if (!l->isRegistered())
{
iter = fixedPriorityListeners->erase(iter);
l->release();
}
else
{
++iter;
}
}
}
if (sceneGraphPriorityListeners && sceneGraphPriorityListeners->empty()) // 如果存储场景图优先级事件监听器的容器已空。
{
listeners->clearSceneGraphListeners(); // 则释放容器所占空间。
}
if (fixedPriorityListeners && fixedPriorityListeners->empty()) // 如果存储固定优先级事件监听器的容器已空。
{
listeners->clearFixedListeners(); // 则释放容器所占空间。
}
};
if (event->getType() == Event::Type::TOUCH) // 如果是触摸事件。
{
// 一个触摸事件对应两种事件监听器,两种事件监听器的ID都要传递。
onUpdateListeners(EventListenerTouchOneByOne::LISTENER_ID);
onUpdateListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
}
else // 如果是其他类型的事件。
{
onUpdateListeners(__getListenerID(event)); // 传递事件所对应的事件监听器ID。
}
if (_inDispatch > 1) // 如果有多于1个事件正在分发,则返回。
return;
CCASSERT(_inDispatch == 1, "_inDispatch should be 1 here."); // 上面的if条件保证了到这里时只有1个事件正在分发。
for (auto iter = _listenerMap.begin(); iter != _listenerMap.end();) // 遍历所有的_listenerMap映射。
{
if (iter->second->empty()) // 如果此listenerID对应的EventListenerVector中两个容器均为空。
{
_priorityDirtyFlagMap.erase(iter->first); // 删除_priorityDirtyFlagMap中此listenerID的映射。
delete iter->second; // 释放EventListenerVector所占用的空间。
iter = _listenerMap.erase(iter); // 删除_listenerMap中此listenerID的映射。
}
else
{
++iter;
}
}
if (!_toAddedListeners.empty()) // 如果有由于事件分发而没有注册完成的事件监听器。
{
for (auto& listener : _toAddedListeners) // 取出每个未注册完成的事件监听器。
{
forceAddEventListener(listener); // 完成注册。
}
_toAddedListeners.clear(); // 清空_toAddedListeners容器。
}
}
(9) void sortEventListeners(const EventListener::ListenerID& listenerID);
将listenerID所对应的EventListenerVector中两个存储事件监听器的容器中的元素分别按照各自的规则以优先级从高到低的顺序排序。
void sortEventListenersOfSceneGraphPriority(const EventListener::ListenerID& listenerID, Node* rootNode);
将listenerID所对应的EventListenerVector中存储场景图优先级事件监听器的容器中所有的事件监听器按照他们所绑定节点的优先级从高到低排序。
void sortEventListenersOfFixedPriority(const EventListener::ListenerID& listenerID);
将listenerID所对应的EventListenerVector中存储固定优先级事件监听器的容器中所有的事件监听器按照他们的优先级从高到低排序,并且获得EventListenerVector::_gt0Index。
listenerID:事件监听器ID。
rootNode:当前正在运行的场景(我理解是当前正显示给用户的场景)
实现源码:
void EventDispatcher::sortEventListeners(const EventListener::ListenerID& listenerID)
{
DirtyFlag dirtyFlag = DirtyFlag::NONE;
auto dirtyIter = _priorityDirtyFlagMap.find(listenerID); // 在_priorityDirtyFlagMap中找listenerID的映射。
if (dirtyIter != _priorityDirtyFlagMap.end()) // 如果找到了。
{
dirtyFlag = dirtyIter->second; // 获取该listenerID所对应的DirtyFlag。
}
if (dirtyFlag != DirtyFlag::NONE) // 如果该listenerID所对应的EventListenerVector中确实有事件监听器容器需要更新。
{
dirtyIter->second = DirtyFlag::NONE; // 清空DirtyFlag。这里先清空的意义在于,当进入下面没有rootNode的分支时,需要将存储场景图优先级事件监听器的容器设置脏标志。
if ((int)dirtyFlag & (int)DirtyFlag::FIXED_PRIORITY) // 如果是存储固定优先级事件监听器的容器需要更新。
{
sortEventListenersOfFixedPriority(listenerID); // 将容器中所有的事件监听器按照他们的优先级从高到低排序,并且获得EventListenerVector::_gt0Index。
}
if ((int)dirtyFlag & (int)DirtyFlag::SCENE_GRAPH_PRIORITY) // 如果是存储场景图优先级事件监听器的容器需要更新。
{
auto rootNode = Director::getInstance()->getRunningScene(); // 获取当前正在运行的场景(我理解是当前正显示给用户的场景)。
if (rootNode)
{
sortEventListenersOfSceneGraphPriority(listenerID, rootNode); // 将存储场景图优先级事件监听器的容器中所有的事件监听器按照他们所绑定节点的优先级从高到低排序。
}
else
{
/* 如果没有rootNode,则要在下次分发事件时再次获取rootNode。
* 因为场景图优先级事件监听器的优先级依赖于所绑定节点的ZOrder,并且所有节点(这里指的不光是被场景图优先级事件监听器所绑定的节点,而指的是程序中所有的节点)
* 好像(这里不确定,是我看EventDispatcher::sortEventListenersOfSceneGraphPriority()所理解的)进行大排序,
* 所以要知道显示在最前面的节点,并且通过它找到所有的节点(显示在最前面节点的子节点)。
* 所以如果没有rootNode,这里要再次设置场景图优先级事件监听器容器的脏标志,在下次分发事件时再次获取rootNode。
*/
dirtyIter->second = DirtyFlag::SCENE_GRAPH_PRIORITY;
}
}
}
}
void EventDispatcher::sortEventListenersOfFixedPriority(const EventListener::ListenerID& listenerID)
{
auto listeners = getListeners(listenerID); // 获取listenerID对应的EventListenerVector。
if (listeners == nullptr)
return;
auto fixedListeners = listeners->getFixedPriorityListeners(); // 获取存储固定优先级事件监听器的容器。
if (fixedListeners == nullptr)
return;
// 将容器中的(固定优先级)事件监听器按照它们的优先级从高到低排序。
std::sort(fixedListeners->begin(), fixedListeners->end(), ](const EventListener* l1, const EventListener* l2) {
return l1->getFixedPriority() < l2->getFixedPriority(); // 所设定的优先级数值越小,其优先级越高。
});
// FIXME: 下面应该修改成“二分法”查找。
int index = 0;
// 找到第一个优先级>=0的事件监听器(优先级<0与优先级>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::sortEventListenersOfSceneGraphPriority(const EventListener::ListenerID& listenerID, Node* rootNode)
{
auto listeners = getListeners(listenerID); // 获取listenerID对应的EventListenerVector。
if (listeners == nullptr)
return;
auto sceneGraphListeners = listeners->getSceneGraphPriorityListeners(); // 获取存储场景图优先级事件监听器的容器。
if (sceneGraphListeners == nullptr)
return;
// Reset priority index
_nodePriorityIndex = 0; // 清空场景图优先级事件监听器所绑定的节点的优先级计数器。
_nodePriorityMap.clear(); // 清空节点与其优先级的映射。
visitTarget(rootNode, true); // 遍历rootNode以及其所有子节点,根据节点的ZOrder计算出节点的优先级。
// 将容器中的(场景图优先级)事件监听器按照它们所绑定节点的优先级从高到低排序。
std::sort(sceneGraphListeners->begin(), sceneGraphListeners->end(), (const EventListener* l1, const EventListener* l2) {
return _nodePriorityMap > _nodePriorityMap;
});
#if DUMP_LISTENER_ITEM_PRIORITY_INFO
log("-----------------------------------");
for (auto& l : *sceneGraphListeners)
{
log(“listener priority: node (%s]%p), priority (%d)”, typeid(*l->_node).name(), l->_node, _nodePriorityMap);
}
#endif
}
(10) EventListenerVector* getListeners(const EventListener::ListenerID& listenerID);
通过listenerID在_listenerMap中找到对应的EventListenerVector。
listenerID:事件监听器ID。
实现源码:
EventDispatcher::EventListenerVector* EventDispatcher::getListeners(const EventListener::ListenerID& listenerID)
{
auto iter = _listenerMap.find(listenerID); // 在_listenerMap中找listenerID的映射。
if (iter != _listenerMap.end()) // 如果找到了。
{
return iter->second; // 返回listenerID对应的EventListenerVector。
}
return nullptr;
}
(11) void visitTarget(Node* node, bool isRootNode);
遍历node以及其所有子节点,根据节点的ZOrder计算出节点的优先级。
node:节点。
isRootNode:是否是树根节点。
实现源码:
void EventDispatcher::visitTarget(Node* node, bool isRootNode)
{
int i = 0;
auto& children = node->getChildren(); // 获取子节点。
auto childrenCount = children.size(); // 获取子节点的数量。
/* 这里很像是二叉树的中序遍历,左中右。只不过这里不是二叉树。
* 对于所有子节点,ZOrder小于0的可看做父节点的左子树,第一个ZOrder大于等于0的可看做左右子树的根,剩余的ZOrder大于0的可看做父节点的右子树。
* 所有节点按照“二叉树中序遍历”的顺序将映射放入_globalZOrderNodeMap,对于同一个父节点的左子节点或右子节点,ZOrder越小越先放入。
*/
if(childrenCount > 0) // 如果有子节点。
{
Node* child = nullptr;
// visit children zOrder < 0
for( ; i < childrenCount; i++ )
{
child = children.at(i); // 依次获取每一个子节点。
if ( child && child->getLocalZOrder() < 0 ) // 左子树。
visitTarget(child, false); // 先被创建映射放入。
else
break; // 看来node的Vector<Node*> _children中的元素一定在某处根据其ZOrder进行了由小到大的排序(猜测)。
}
if (_nodeListenersMap.find(node) != _nodeListenersMap.end()) // 如果在_nodeListenersMap中能找到node的映射。
{
_globalZOrderNodeMap.push_back(node); // 再放入左右子树的根的映射。
}
for( ; i < childrenCount; i++ ) // 右子树。
{
child = children.at(i);
if (child)
visitTarget(child, false); // 最后被创建映射放入。
}
}
else // 如果没有子节点。
{
if (_nodeListenersMap.find(node) != _nodeListenersMap.end()) // 如果在_nodeListenersMap中能找到node的映射。
{
_globalZOrderNodeMap.push_back(node); // 将node与其ZOrder的映射放入_globalZOrderNodeMap中。
}
}
if (isRootNode) // 如果是rootNode节点。
{
std::vector<float> globalZOrders;
globalZOrders.reserve(_globalZOrderNodeMap.size());
for (const auto& e : _globalZOrderNodeMap) // 依次获取_globalZOrderNodeMap中的每个映射。
{
globalZOrders.push_back(e.first); // 存储_globalZOrderNodeMap中拥有的每一种ZOrde的值。
}
// 将globalZOrders中的ZOrder值按照从小到大排序。
std::sort(globalZOrders.begin(), globalZOrders.end(), ](const float a, const float b){
return a < b;
});
for (const auto& globalZ : globalZOrders) // 获取每一种ZOrder。
{
for (const auto& n : _globalZOrderNodeMap) // 获取设置为此ZOrder的每一个node。
{
/* 比如_globalZOrderNodeMap中有映射“1 <--> {节点①, 节点③}”,说明节点①和节点③的ZOrder都是1。
* 可是优先级总要有个先后顺序,那么就规定先放入_globalZOrderNodeMap的node优先级就低,后放入的就高。
* 而node放入_globalZOrderNodeMap的顺序是根据上面“二叉树中序遍历”的规则决定的。
*/
_nodePriorityMap = ++_nodePriorityIndex; // 节点的优先级从1开始。
}
}
_globalZOrderNodeMap.clear();
// 清空_globalZOrderNodeMap。这个变量只在EventDispatcher::visitTarget()中使用,为什么不定义成局部变量。
}
}
关键点总结:
1、EventDispatcher::visitTarget()根据所有节点的ZOrder以及一套规则,计算出了所有节点在_nodePriorityMap中的值,也就是节点的优先级。
而这个函数只有在处理场景图优先级事件监听器的时候才会调用,在EventDispatcher::sortEventListenersOfSceneGraphPriority()中可以看到,
最终计算出的_nodePriorityMap中的值实际上决定了场景图优先级事件的优先级。
因为场景图优先级的事件在被创建时其优先级均被设置为0,同时只有场景图优先级的事件监听器需要绑定节点,所以才借用被绑定节点的ZOrder来决定
优先级同为0的场景图优先级事件的实际优先级。
这样最终能推断出,ZOrder越大(显示的越靠前) --> 优先级越高;ZOrder相同时在整个node与其子节点的树形结构中,越靠右边的节点 --> 优先级越高。
(12) void removeEventListener(EventListener* listener);
移除一个指定的事件监听器。
void removeEventListenersForListenerID(const EventListener::ListenerID& listenerID);
移除指定listenerID的所有事件监听器。
void removeEventListenersForType(EventListener::Type listenerType);
移除指定类型的所有事件监听器。
void removeEventListenersForTarget(Node* target, bool recursive = false);
移除与指定的node绑定的所有事件监听器。
void removeCustomEventListeners(const std::string& customEventName);
移除指定的用户自定义事件监听器名称的所有用户自定义事件监听器。
void removeAllEventListeners();
移除所有的事件监听器(内部事件监听器不会被移除)。
listener:待被移除的事件监听器。
listenerID:指定的待被移除的事件监听器的listenerID。
listenerType:指定的待被移除的事件监听器类型。
target:指定的待被移除的事件监听器所绑定的节点。
recursive:是否递归的对子节点做相同的操作。
customEventName:指定的待被移除的用户自定义事件监听器名称。
实现源码:
void EventDispatcher::removeEventListener(EventListener* listener)
{
if (listener == nullptr)
return;
bool isFound = false; // 是否找到了待移除的事件监听器。
// 在指定容器中查找待移除的事件监听器,如果找到了移除事件监听器或者标记此事件监听器待移除(注销)。
auto removeListenerInVector = &](std::vector<EventListener*>* listeners){
if (listeners == nullptr)
return;
for (auto iter = listeners->begin(); iter != listeners->end(); ++iter) // 遍历容器中的每一个事件监听器。
{
auto l = *iter; // iter是容器中数据的地址(&(EventListener*)),这里需要获得容器中的具体元素(EventListener*)。
if (l == listener) // 如果是待被移除的事件监听器。
{
/* 这里应该是对应函数结尾处的CC_SAFE_RELEASE()。
* 不过这里有必要单独放在CC_SAFE_RETAIN()与CC_SAFE_RELEASE()中吗,EventDispatcher::addEventListener()不是已经retain过了?
*/
CC_SAFE_RETAIN(l);
l->setRegistered(false); // 注销此事件监听器。
if (l->getAssociatedNode() != nullptr) // 如果此事件监听器有绑定的节点(场景图优先级事件监听器)。
{
dissociateNodeAndEventListener(l->getAssociatedNode(), l); // 从_nodeListenersMap中移除此事件监听器。
l->setAssociatedNode(nullptr); // 设置绑定的节点为nullptr。
}
if (_inDispatch == 0) // 如果没有正在分发的事件。
{
listeners->erase(iter); // 从容器中移除此事件监听器。
CC_SAFE_RELEASE(l); // 减少该事件监听器的引用计数。
}
isFound = true; // 标识已找到了待移除的事件监听器。
break;
}
}
};
for (auto iter = _listenerMap.begin(); iter != _listenerMap.end();)
// 遍历_listenerMap中的每一个映射(为何不listener->getListenerID(),然后找到对应的EventListenerVector?)。
{
auto listeners = iter->second; // 获取此listenerID对应的EventListenerVector。
auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); // 获取存储固定优先级事件监听器的容器。
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); // 获取存储场景图优先级事件监听器的容器。
// 先从sceneGraphPriorityListeners中找待移除的事件监听器,如果没找到再从fixedPriorityListeners中找。
removeListenerInVector(sceneGraphPriorityListeners); // 在存储场景图优先级事件监听器的容器中查找待移除的事件监听器,如果找到了移除事件监听器或者标记此事件监听器待移除(注销)。
if (isFound) // 如果找到了待移除的事件监听器。
{
setDirty(listener->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY); // 场景图优先级事件监听器的容器中有元素被移除,设置脏标志。
}
else // 如果没找到。
{
removeListenerInVector(fixedPriorityListeners); // 在存储固定优先级事件监听器的容器中查找待移除的事件监听器,如果找到了移除事件监听器或者标记此事件监听器待移除(注销)。
if (isFound) // 如果找到了待移除的事件监听器。
{
setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRIORITY); // 固定优先级事件监听器的容器中有元素被移除,设置脏标志。
}
}
// 如果没有正在分发的事件,则待移除的事件监听器应已被从存储事件监听器的容器中移除。
#if CC_NODE_DEBUG_VERIFY_EVENT_LISTENERS
CCASSERT(_inDispatch != 0 ||
!sceneGraphPriorityListeners ||
std::count(sceneGraphPriorityListeners->begin(), sceneGraphPriorityListeners->end(), listener) == 0,
“Listener should be in no lists after this is done if we’re not currently in dispatch mode.”);
CCASSERT(_inDispatch != 0 ||
!fixedPriorityListeners ||
std::count(fixedPriorityListeners->begin(), fixedPriorityListeners->end(), listener) == 0,
"Listener should be in no lists after this is done if we're not currently in dispatch mode.");
#endif
if (iter->second->empty()) // 如果此listenerID所对应的EventListenerVector中两个存储事件监听器的容器均为空。
{
_priorityDirtyFlagMap.erase(listener->getListenerID()); // 移除此listenerID与DirtyFlag的映射。
auto list = iter->second; // 获取此listenerID所对应的EventListenerVector。
iter = _listenerMap.erase(iter); // 移除此listenerID与对应的EventListenerVector的映射。
CC_SAFE_DELETE(list); // 释放EventListenerVector所占用的空间。
}
else // 否则。
{
++iter; // _listenerMap中的下一个映射。
}
if (isFound) // 如果找到了待移除的事件监听器。
break; // 跳出遍历_listenerMap的循环。
}
if (isFound) // 如果找到了待移除的事件监听器。
{
CC_SAFE_RELEASE(listener); // 这里是对应removeListenerInVector()中的CC_SAFE_RETAIN()。
}
else // 如果没有找到。
{
for(auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); ++iter) // 在_toAddedListeners中找。
{
if (*iter == listener) // 如果找到了。
{
listener->setRegistered(false); // 注销此事件监听器。
listener->release(); // 减少该事件监听器的引用计数。
_toAddedListeners.erase(iter); // 从_toAddedListeners中移除此事件监听器。
break;
}
}
}
}
void EventDispatcher::removeEventListenersForListenerID(const EventListener::ListenerID& listenerID)
{
auto listenerItemIter = _listenerMap.find(listenerID); // 在_listenerMap中找listenerID的映射。
if (listenerItemIter != _listenerMap.end()) // 如果找到了。
{
auto listeners = listenerItemIter->second; // 获取此listenerID所对应的EventListenerVector。
auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); // 获取存储固定优先级事件监听器的容器。
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); // 获取存储场景图优先级事件监听器的容器。
auto removeAllListenersInVector = &](std::vector<EventListener*>* listenerVector){ // 移除容器中所有事件监听器的匿名函数。
if (listenerVector == nullptr)
return;
for (auto iter = listenerVector->begin(); iter != listenerVector->end();) // 遍历容器中的每一个事件监听器。
{
auto l = *iter; // iter是容器中数据的地址(&(EventListener*)),这里需要获得容器中的具体元素(EventListener*)。
l->setRegistered(false); // 注销事件监听器。
if (l->getAssociatedNode() != nullptr) // 如果此事件监听器有绑定的节点(场景图优先级事件监听器)。
{
dissociateNodeAndEventListener(l->getAssociatedNode(), l); // 从_nodeListenersMap中移除此事件监听器。
l->setAssociatedNode(nullptr); // 设置绑定的节点为nullptr。
}
if (_inDispatch == 0) // 如果没有正在分发的事件。
{
iter = listenerVector->erase(iter); // 从容器中移除此事件监听器。
CC_SAFE_RELEASE(l); // 减少此事件监听器的引用计数。
}
else // 如果有正在分发的事件。
{
++iter; // 下一个事件监听器。
}
}
};
removeAllListenersInVector(sceneGraphPriorityListeners); // 移除存储场景图优先级事件监听器容器中的所有事件监听器。
removeAllListenersInVector(fixedPriorityListeners); // 移除存储固定优先级事件监听器容器中的所有事件监听器。
_priorityDirtyFlagMap.erase(listenerID); // 从_priorityDirtyFlagMap中删除此listenerID的映射。
if (!_inDispatch) // 如果没有正在分发的事件。
{
listeners->clear(); // 清空EventListenerVector。
delete listeners; // 释放EventListenerVector所占用的空间。
_listenerMap.erase(listenerItemIter); // 从_listenerMap中删除此listenerID的映射。
}
}
for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end();) // 看看_toAddedListeners中还有没有此listenerID的事件监听器。
{
if ((*iter)->getListenerID() == listenerID) // 如果有。
{
(*iter)->setRegistered(false); // 注销此事件监听器。
(*iter)->release(); // 减少此事件监听器的引用计数。
iter = _toAddedListeners.erase(iter); // 从_toAddedListeners中移除此事件监听器。
}
else
{
++iter;
}
}
}
void EventDispatcher::removeEventListenersForType(EventListener::Type listenerType)
{
/* 根据事件监听器的类型,移除该类型的所有事件监听器。
- 为什么没有FOCUS和GAME_CONTROLLER?
*/
if (listenerType == EventListener::Type::TOUCH_ONE_BY_ONE)
{
removeEventListenersForListenerID(EventListenerTouchOneByOne::LISTENER_ID);
}
else if (listenerType == EventListener::Type::TOUCH_ALL_AT_ONCE)
{
removeEventListenersForListenerID(EventListenerTouchAllAtOnce::LISTENER_ID);
}
else if (listenerType == EventListener::Type::MOUSE)
{
removeEventListenersForListenerID(EventListenerMouse::LISTENER_ID);
}
else if (listenerType == EventListener::Type::ACCELERATION)
{
removeEventListenersForListenerID(EventListenerAcceleration::LISTENER_ID);
}
else if (listenerType == EventListener::Type::KEYBOARD)
{
removeEventListenersForListenerID(EventListenerKeyboard::LISTENER_ID);
}
else
{
CCASSERT(false, “Invalid listener type!”);
}
}
void EventDispatcher::removeEventListenersForTarget(Node* target, bool recursive/* = false */)
{
_nodePriorityMap.erase(target); // _nodePriorityMap中删除该node的映射。
_dirtyNodes.erase(target); // _dirtyNodes中删除该node。
auto listenerIter = _nodeListenersMap.find(target); // 在_nodeListenersMap中找该node的映射。
if (listenerIter != _nodeListenersMap.end()) // 如果找到了。
{
auto listeners = listenerIter->second; // 获取存储与此node绑定的所有(场景图优先级)事件监听器的容器。
auto listenersCopy = *listeners;
// 删除容器中每一个(场景图优先级)事件监听器。
for (auto& l : listenersCopy)
{
removeEventListener(l);
}
}
for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); ) // 遍历_toAddedListeners中每一个事件监听器。
{
EventListener * listener = *iter;
if (listener->getAssociatedNode() == target) // 如果事件监听器所绑定的节点是所指定的节点。
{
listener->setAssociatedNode(nullptr); // 设置绑定的节点为nullptr。
listener->setRegistered(false); // 注销此事件监听器。
listener->release(); // 减少此事件监听器的引用计数。
iter = _toAddedListeners.erase(iter); // 从_toAddedListeners中移除此事件监听器。
}
else
{
++iter;
}
}
if (recursive) // 是否递归的对node的子节点做相同的操作。
{
const auto& children = target->getChildren(); // 获得node的子节点。
for (const auto& child : children) // 对每一个子节点做相同的操作。
{
removeEventListenersForTarget(child, true);
}
}
}
void EventDispatcher::removeCustomEventListeners(const std::string& customEventName)
{
removeEventListenersForListenerID(customEventName); // 用户自定义事件监听器的名称也就是用户自定义事件监听器ID。
}
void EventDispatcher::removeAllEventListeners()
{
bool cleanMap = true;
std::vectorEventListener::ListenerID types(_listenerMap.size()); // 这个变量的意义没有明白,觉得没必要。
for (const auto& e : _listenerMap) // 遍历_listenerMap中的每一个映射。
{
if (_internalCustomListenerIDs.find(e.first) != _internalCustomListenerIDs.end()) // 如果是内部事件监听器。
{
cleanMap = false;
}
else // 如果不是内部事件监听器。
{
types.push_back(e.first);
// 为什么不在这里直接调用removeEventListenersForListenerID()?
}
}
for (const auto& type : types)
{
removeEventListenersForListenerID(type); // 根据指定的listenerID移除对应的事件监听器。
}
if (!_inDispatch && cleanMap) // 如果没有正在分发事件并且_listenerMap中没有存储内部事件监听器。
{
_listenerMap.clear(); // 清空_listenerMap。
}
}
(13) void setPriority(EventListener* listener, int fixedPriority);
设置固定优先级事件监听器的优先级。
listener:事件监听器。
fixedPriority:设置的优先级。
实现源码:
void EventDispatcher::setPriority(EventListener* listener, int fixedPriority)
{
if (listener == nullptr)
return;
for (auto iter = _listenerMap.begin(); iter != _listenerMap.end(); ++iter) // 遍历_listenerMap中的每个映射。
{
auto fixedPriorityListeners = iter->second->getFixedPriorityListeners(); // 依次获得每个EventListenerVector中的存储固定优先级的事件监听器容器。
if (fixedPriorityListeners) // 如果容器存在。
{
auto found = std::find(fixedPriorityListeners->begin(), fixedPriorityListeners->end(), listener); // 在容器中查找此事件监听器。
if (found != fixedPriorityListeners->end()) // 如果找到了。
{
// 只能设置固定优先级事件监听器的优先级,所以事件监听器所绑定的节点一定为nullptr。
CCASSERT(listener->getAssociatedNode() == nullptr, "Can't set fixed priority with scene graph based listener.");
if (listener->getFixedPriority() != fixedPriority) // 如果事件监听器本身的优先级与待设定的值不相同。
{
listener->setFixedPriority(fixedPriority); // 设置事件监听器的优先级为指定的值。
setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRIORITY); // 设置此事件监听器所在EventListenerVector中存放固定优先级事件监听器容器的脏标志。
}
return;
}
}
}
}
关键点总结:
1、为什么要遍历_listenerMap中的每个映射来确定listener对应哪个EventListenerVector?直接使用_listenerMap.find(listener->getListenerID())不就可以了?
(14) void debugCheckNodeHasNoEventListenersOnDestruction(Node* node);
验证当node被系构时,没有与其绑定的事件监听器。Node::~Node()中使用。
node:需要被验证的node。
实现源码:
void EventDispatcher::debugCheckNodeHasNoEventListenersOnDestruction(Node* node)
{
for (const auto & keyValuePair : _listenerMap) // 遍历_listenerMap中的每一个映射。
{
const EventListenerVector * eventListenerVector = keyValuePair.second; // 获取listenerID对应的EventListenerVector。
if (eventListenerVector) // 如果EventListenerVector存在。
{
if (eventListenerVector->getSceneGraphPriorityListeners()) // 如果存储场景图优先级事件监听器的容器存在。
{
for (EventListener * listener : *eventListenerVector->getSceneGraphPriorityListeners()) // 遍历容器中每一个场景图优先级事件监听器。
{
CCASSERT(!listener || // 如果事件监听器存在。
listener->getAssociatedNode() != node, // 并且事件监听器没有绑定此node。
"Node should have no event listeners registered for it upon destruction!");
}
}
}
}
for (const auto & keyValuePair : _nodeListenersMap) // 遍历_nodeListenersMap中的每一个映射。
{
CCASSERT(keyValuePair.first != node, "Node should have no event listeners registered for it upon destruction!"); // 即将被系构的node不能在_nodeListenersMap中存有映射。
/* 以下这部分验证有些多余吧。
* _nodeListenersMap中存储的是“与节点所绑定的所有场景图优先级的事件监听器与该节点之间的映射”,
* 上面已经验证了_nodeListenersMap中没有待被系构的node,何必还要验证其他node的映射?
*/
if (keyValuePair.second)
{
for (EventListener * listener : *keyValuePair.second)
{
CCASSERT(listener->getAssociatedNode() != node,
“Node should have no event listeners registered for it upon destruction!”);
}
}
}
for (const auto & keyValuePair : _nodePriorityMap) // 遍历_nodePriorityMap中的每一个映射。
{
CCASSERT(keyValuePair.first != node,
"Node should have no event listeners registered for it upon destruction!"); // 即将被系构的node不能在_nodePriorityMap中存有映射。
}
for (EventListener * listener : _toAddedListeners) // 遍历_toAddedListeners中的每一个映射。
{
CCASSERT(listener->getAssociatedNode() != node,
"Node should have no event listeners registered for it upon destruction!"); // 即将被系构的node不能在_toAddedListeners中存有映射。
}
for (Node * dirtyNode : _dirtyNodes) // 遍历_dirtyNodes中的每一个映射。
{
CCASSERT(dirtyNode != node,
"Node should have no event listeners registered for it upon destruction!"); // 即将被系构的node不能在_dirtyNodes中存有映射。
}
}
三、内部函数:
(1) static EventListener::ListenerID __getListenerID(Event* event)
获取事件所对应的事件监听器ID。
实现源码:
static EventListener::ListenerID __getListenerID(Event* event)
{
EventListener::ListenerID ret;
switch (event->getType()) // 获取事件的类型。
{
case Event::Type::ACCELERATION:
ret = EventListenerAcceleration::LISTENER_ID;
break;
case Event::Type::CUSTOM:
{
auto customEvent = static_cast<EventCustom*>(event);
ret = customEvent->getEventName(); // 只有自定义事件监听器ID存储在自己对应的事件类(EventCustom)中,其他的都存储在自己对应的事件监听器类中。
}
break;
case Event::Type:
ret = EventListenerKeyboard::LISTENER_ID;
break;
case Event::Type:
ret = EventListenerMouse::LISTENER_ID;
break;
case Event::Type::FOCUS:
ret = EventListenerFocus::LISTENER_ID;
break;
case Event::Type::TOUCH:
CCASSERT(false, “Don’t call this method if the event is for touch.”); // 触摸事件在这个函数之前应该已经传递给专门的函数处理了,不应该调用到这里。
break;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
case Event::Type::GAME_CONTROLLER:
ret = EventListenerController::LISTENER_ID;
break;
#endif
default:
CCASSERT(false, “Invalid type!”);
break;
}
return ret;
}
EventListenerVector:
一、成员变量:
private:
std::vector<EventListener*>* _fixedListeners; // 存储固定优先级事件监听器的容器。
std::vector<EventListener*>* _sceneGraphListeners; // 存储场景图优先级事件监听器的容器。
ssize_t _gt0Index; // _fixedListeners容器中第一个优先级>=0的事件监听器的索引(在分发事件的过程中_fixedListeners容器中的事件监听器会按照他们的优先级数值从小到大排序,即优先级从高到低排序)。
二、成员方法:
一些get/set方法在这里不一一列举。
(1) void push_back(EventListener* item);
将事件监听器放入EventListenerVector中对应的容器内,如果对应的容器之前没有被创建,则创建它。
实现源码:
void EventDispatcher::EventListenerVector::push_back(EventListener* listener)
{
#if CC_NODE_DEBUG_VERIFY_EVENT_LISTENERS
// std::count()验证事件监听器在容器中出现的次数,事件监听器不能被重复添加进容器。
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); // 容器中最多能存储100个事件监听器。
}
_sceneGraphListeners->push_back(listener); // 将事件监听器放入容器。
}
else // 固定优先级的事件监听器。
{
if (_fixedListeners == nullptr) // 如果容器还没有被创建。
{
_fixedListeners = new std::vector<EventListener*>(); // 创建容器。
_fixedListeners->reserve(100); // 容器中最多能存储100个事件监听器。
}
_fixedListeners->push_back(listener); // 将事件监听器放入容器。
}
}
关键点总结:
1、如果不开启CC_NODE_DEBUG_VERIFY_EVENT_LISTENERS,同一个事件监听器就允许被重复添加了?允许被重复添加的意义何在?
2、EventListenerVector没有选择在构造函数中为_sceneGraphListeners和_fixedListeners分配空间,而是在使用它们的时候才分配空间,可能是为了节省空间的考虑,因为事件监听器对于程序不是必需的。
(2) void clearSceneGraphListeners();
void clearFixedListeners();
void clear();
移除存储事件监听器的容器。
实现源码:
void EventDispatcher::EventListenerVector::clearSceneGraphListeners()
{
if (_sceneGraphListeners) // 如果存储场景图优先级事件监听器的容器已经分配了空间。
{
_sceneGraphListeners->clear(); // 清空容器。
delete _sceneGraphListeners; // 释放为容器分配的空间。
_sceneGraphListeners = nullptr; // 野指针指向空。
}
}
void EventDispatcher::EventListenerVector::clearFixedListeners()
{
if (_fixedListeners) // 如果存储固定优先级事件监听器的容器已经分配了空间。
{
_fixedListeners->clear(); // 清空容器。
delete _fixedListeners; // 释放为容器分配的空间。
_fixedListeners = nullptr; // 野指针指向空。
}
}
void EventDispatcher::EventListenerVector::clear()
{
clearSceneGraphListeners(); // 移除存储场景图优先级事件监听器的容器。
clearFixedListeners(); // 移除存储固定优先级事件监听器的容器。
}
关键点总结:
1、觉得分成三个函数比较乱,还不如像EventListenerVector::push_back()那样,都在EventListenerVector::clear()中处理。
(3) size_t size() const;
获取EventListenerVector中存储了多少个事件监听器。
实现源码:
size_t EventDispatcher::EventListenerVector::size() const
{
size_t ret = 0;
if (_sceneGraphListeners)
ret += _sceneGraphListeners->size(); // 存储了多少个场景图优先级事件监听器。
if (_fixedListeners)
ret += _fixedListeners->size(); // 存储了多少个固定优先级事件监听器。
return ret; // 返回两种监听器数量的和。
}
(4) bool empty() const;
返回EventListenerVector的两个容器是否都为空。
实现源码:
bool EventDispatcher::EventListenerVector::empty() const
{
return (_sceneGraphListeners == nullptr || _sceneGraphListeners->empty()) // 存储场景图优先级事件监听器的容器没有分配空间或者没有存储元素。
&& (_fixedListeners == nullptr || _fixedListeners->empty()); // 存储固定优先级事件监听器的容器没有分配空间或者没有存储元素。
}
DispatchGuard:
一、成员变量:
private:
int& _count;
// 当前正在分发的事件数量的引用。
二、成员方法:
(1) DispatchGuard(int& count):
_count(count) // 实际相当于int &_count = _inDispatch。
{
++_count; // 当前正在分发的事件数量(_inDispatch)+1。
}
~DispatchGuard()
{
--_count; // 当前正在分发的事件数量(_inDispatch)-1。
}
关键点总结:
1、成员变量不是普通的占用空间的变量,而是变量的引用。它实际将作为EventDispatcher::_inDispatch的引用,这样在构造函数和析构函数中对_count的增加和减少,实际上是对EventDispatcher::_inDispatch的增加和减少。
总结:
1、
固定优先级事件是根据设置的优先级数值决定优先级,数值越小优先级越高;场景图优先级事件是根据所绑定节点的ZOrder的数值决定优先级,数值越大(显示越靠前)优先级越高。
小于零的固定优先级事件 > 所有场景图优先级事件 > 大于零的固定优先级事件。
2、从固定优先级事件监听器不需要绑定节点,以及场景图优先级事件的优先级计算方法这两点来看,场景图优先级事件监听器绑定节点的意义仅在于借助于绑定节点的ZOrder计算出优先级。
如果场景图优先级事件的优先级(不是全部默认是0)也可以随意指定的话,也许场景图优先级事件监听器根本不用绑定节点。
3、优先级 <–> 事件,事件 <–> 事件监听器,所以事件监听器与优先级才有了间接的一一对应关系。
为何要把优先级(_fixedPriority)设定为事件监听器的属性(EventListener::_fixedPriority)?我觉得他们并没有直接的一一对应关系,设定为事件的属性(Event::_fixedPriority)更加贴切。