继承Ref类,相当于给这个类加上了cocos2dx的内存管理机制
class UIEventDispatcher : public cocos2d::Ref
private成员变量:
_dispatching:一个判断标志,判断自身是否正在派遣事件。在构造类实例时默认初始为0.
EventCallbackItem:callBack事件回调函数。eventType事件类型,tag事件标记(EventTag类),dispatching事件是否正在派遣的标志
struct EventCallbackItem
{
EventCallback callback;
int eventType;
EventTag tag;
int dispatching;
};
std::vector<EventCallbackItem*> _callbacks;
int _dispatching;
EventCallback一个参数为EventContext* context返回为空的函数指针
typedef std::function<void(EventContext* context)> EventCallback;
EventContext
事件上下文类:成员变量
//绑定要派送这个上下文的事件调度器(即触发这个事件的object)
cocos2d::Ref* _sender;
//inputEvent输入事件类的一些信息(触摸事件的位置,按键事件的键盘,点击事件的次数等等)
InputEvent* _inputEvent;
//事件的数据value
cocos2d::Value _dataValue;
//指向事件数据的指针
void* _data;
//冒泡事件,是否停止传播这个事件,用于判断是否向父节点继续传播
bool _isStopped;
//是否默认阻止,作为派遣事件的返回,做一些派遣事件的后续处理。目前来看,在GObject的touchMove里进行DragStart事件,以及slider进行Changed事件有判断
bool _defaultPrevented;
//捕获触摸事件的判断,1为捕获触摸事件,2为释放触摸事件
int _touchCapture;
//事件类型
int _type;
friend class UIEventDispatcher;
EventTag类注意有个value值,isNone是value是否0的判断就行,其他函数就是EventTag的构造和一些操作符的重载
class EventTag
{
public:
//...
//...
bool isNone() const { return _value == 0; }
private:
uintptr_t _value;
};
public成员函数:
构造和析构:
UIEventDispatcher::UIEventDispatcher() :_dispatching(0)
{
}
UIEventDispatcher::~UIEventDispatcher()
{
_dispatching = 0;
removeEventListeners();
}
根据事件类型添加事件监听:
如果有tag标记的监听者,则判断是否更新旧的监听回调。否则增加新的监听者
无tag的监听者直接加入
void addEventListener(int eventType, const EventCallback& callback) { return addEventListener(eventType, callback, EventTag::None); }
void UIEventDispatcher::addEventListener(int eventType, const EventCallback& callback, const EventTag& tag)
{
if (!tag.isNone())
{
for (auto it = _callbacks.begin(); it != _callbacks.end(); it++)
{
if ((*it)->eventType == eventType && (*it)->tag == tag)
{
(*it)->callback = callback;
return;
}
}
}
EventCallbackItem* item = new EventCallbackItem();
item->callback = callback;
item->eventType = eventType;
item->tag = tag;
item->dispatching = 0;
_callbacks.push_back(item);
}
根据事件类型删除事件监听
void removeEventListener(int eventType) { removeEventListener(eventType, EventTag::None); }
有tag则删除tag对应的监听,无tag则删除所有tag为None的监听
如果当前正在派遣事件,则把监听回调置空,否则直接删除监听
void UIEventDispatcher::removeEventListener(int eventType, const EventTag& tag)
{
if (_callbacks.empty())
return;
for (auto it = _callbacks.begin(); it != _callbacks.end(); )
{
if ((*it)->eventType == eventType && ((*it)->tag == tag || tag.isNone()))
{
if (_dispatching > 0)
{
(*it)->callback = nullptr;
it++;
}
else
{
delete (*it);
it = _callbacks.erase(it);
}
}
else
it++;
}
}
删除全部监听者,与单个删除同理
void UIEventDispatcher::removeEventListeners()
{
if (_callbacks.empty())
return;
if (_dispatching > 0)
{
for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
(*it)->callback = nullptr;
}
else
{
for (auto it = _callbacks.begin(); it != _callbacks.end(); it++)
delete (*it);
_callbacks.clear();
}
}
判断是否有对应的事件类型监听
比较简单,没啥说的
bool hasEventListener(int eventType) const { return hasEventListener(eventType, EventTag::None); }
bool hasEventListener(int eventType, const EventTag& tag) const;
事件派遣
设置事件上下文类的数据:设置自身为派送这个事件的调度器和事件的类型。_activeProcessor是InputProcessor静态成员,用来判断有无输入事件(触摸,按键,点击等等),事件的数据
bool UIEventDispatcher::dispatchEvent(int eventType, void* data, const Value& dataValue)
{
if (_callbacks.size() == 0)
return false;
EventContext context;
context._sender = this;
context._type = eventType;
if (InputProcessor::_activeProcessor)
context._inputEvent = InputProcessor::_activeProcessor->getRecentInput();
context._dataValue = dataValue;
context._data = data;
doDispatch(eventType, &context);
return context._defaultPrevented;
}
进行事件的派遣:doDispatch
void UIEventDispatcher::doDispatch(int eventType, EventContext* context)
{
retain();
//设置正在派遣的数量
_dispatching++;
context->_sender = this;
//是否有需要删除的监听者
bool hasDeletedItems = false;
size_t cnt = _callbacks.size(); //dont use iterator, because new item would be added in callback.
for (size_t i = 0; i < cnt; i++)
{
EventCallbackItem* ci = _callbacks[i];
//事件回调为空的,需要删除无用的监听者
if (ci->callback == nullptr)
{
hasDeletedItems = true;
continue;
}
//对应事件类型的监听者触发回调
if (ci->eventType == eventType)
{
ci->dispatching++;
//重置触摸捕获
context->_touchCapture = 0;
//触发回调
ci->callback(context);
ci->dispatching--;
//判断是否捕获触摸,并且自身为GObject对象,则设置自身为该触摸事件的监听之一(触摸事件是TouchInfo类,有个vector成员变量,储存这个触摸事件的监听者)
if (context->_touchCapture != 0 && dynamic_cast<GObject*>(this))
{
//捕获触摸监听者
if (context->_touchCapture == 1 && eventType == UIEventType::TouchBegin)
context->getInput()->getProcessor()->addTouchMonitor(context->getInput()->getTouchId(), dynamic_cast<GObject*>(this));
//释放触摸监听者
else if (context->_touchCapture == 2)
context->getInput()->getProcessor()->removeTouchMonitor(dynamic_cast<GObject*>(this));
}
}
}
_dispatching--;
//判断是否需要删除无用监听者,并删除
if (hasDeletedItems && _dispatching == 0)
{
for (auto it = _callbacks.begin(); it != _callbacks.end(); )
{
if ((*it)->callback == nullptr)
{
delete (*it);
it = _callbacks.erase(it);
}
else
it++;
}
}
release();
}
根据事件类型进行冒泡派遣
与单独派送类似,只是不用设置派送事件的对象
bool UIEventDispatcher::bubbleEvent(int eventType, void* data, const Value& dataValue)
{
EventContext context;
if (InputProcessor::_activeProcessor)
context._inputEvent = InputProcessor::_activeProcessor->getRecentInput();
context._type = eventType;
context._dataValue = dataValue;
context._data = data;
doBubble(eventType, &context);
return context._defaultPrevented;
}
void UIEventDispatcher::doBubble(int eventType, EventContext* context)
{
//parent maybe disposed in callbacks
//获取父节点的弱引用
WeakPtr wptr(((GObject*)this)->findParent());
if (!_callbacks.empty())
{
//重置冒泡标志
context->_isStopped = false;
//进行自身事件回调
doDispatch(eventType, context);
if (context->_isStopped)
return;
}
GObject* p = wptr.ptr();
//如果回调中父节点还在,则调用父节点冒泡派遣
if (p)
p->doBubble(eventType, context);
}
判断某类型事件是否正在派遣
bool UIEventDispatcher::isDispatchingEvent(int eventType)
{
for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
{
if ((*it)->eventType == eventType)
return (*it)->dispatching > 0;
}
return false;
}