当前位置:   article > 正文

fairygui的cocos2dx类源码分析:UIEventDispatcher类_gairygui导出的源码

gairygui导出的源码

继承Ref类,相当于给这个类加上了cocos2dx的内存管理机制

class UIEventDispatcher : public cocos2d::Ref
  • 1

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

EventCallback一个参数为EventContext* context返回为空的函数指针

typedef std::function<void(EventContext* context)> EventCallback;
  • 1

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

EventTag类注意有个value值,isNone是value是否0的判断就行,其他函数就是EventTag的构造和一些操作符的重载

class EventTag
{
public:
	//...
	//...
    bool isNone() const { return _value == 0; }
private:
    uintptr_t _value;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

public成员函数:

构造和析构:

UIEventDispatcher::UIEventDispatcher() :_dispatching(0)
{
}

UIEventDispatcher::~UIEventDispatcher()
{
    _dispatching = 0;
    removeEventListeners();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

根据事件类型添加事件监听:
如果有tag标记的监听者,则判断是否更新旧的监听回调。否则增加新的监听者
无tag的监听者直接加入

void addEventListener(int eventType, const EventCallback& callback) { return addEventListener(eventType, callback, EventTag::None); }
  • 1
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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

根据事件类型删除事件监听

void removeEventListener(int eventType) { removeEventListener(eventType, EventTag::None); }
  • 1

有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++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

删除全部监听者,与单个删除同理

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

判断是否有对应的事件类型监听
比较简单,没啥说的

bool hasEventListener(int eventType) const { return hasEventListener(eventType, EventTag::None); }
bool hasEventListener(int eventType, const EventTag& tag) const;
  • 1
  • 2

事件派遣
设置事件上下文类的数据:设置自身为派送这个事件的调度器和事件的类型。_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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

进行事件的派遣: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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

根据事件类型进行冒泡派遣
与单独派送类似,只是不用设置派送事件的对象

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

判断某类型事件是否正在派遣

bool UIEventDispatcher::isDispatchingEvent(int eventType)
{
    for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
    {
        if ((*it)->eventType == eventType)
            return (*it)->dispatching > 0;
    }
    return false;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/959508
推荐阅读
相关标签
  

闽ICP备14008679号