赞
踩
继承Ref类,相当于给这个类加上了cocos2dx的内存管理机制
class UIEventDispatcher : public cocos2d::Ref
_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;
};
构造和析构:
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;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。