最近在用cocostudio来做背包系统的UI,在一个layer中添加了cocostudio 的UI(scrollview),发现点击事件在scrollview中的时候layer 是接收不到的,于是就想通过提高layer的触摸优先级来解决,发现即使把layer优先级提高到-1000还是没有反应。
发现加载后点击事件在scrollview之外的地方是可以被layer(scrollview的parent)响应的,但是一旦到了scrollview的区域就没有响应了,事件肯定是被scrollview处理掉了,无法传递到layer中 即使layer的触摸优先级达到了-1000
于是研究了一下 3.0 版本的事件分发机制,现总结如下:
cocos2dx 3.0 事件分发机制和以前的2.x已经不一样了,最明显的区别是用两个vector来存储事件监听器 在分发的时候排序后按照一定的规则进行。
首先3.0中使用两个vector来存储事件监听器:
std::vector<EventListener*>* _fixedListeners; 存储fixedListener
std::vector<EventListener*>* _sceneGraphListeners; 存储SceneGraphListener
两个vector存储的监听器类型是一样的,只是在添加监听器的时候由coder手动指定要添加的容器,如你想添加到fixedListener中,或者是你想添加到sceneGraphListeners中(这一步是由程序员决定的,当然如果你用cocostudio等UI编辑器加载UI的话就是有UIReader决定的了)
添加之后在接下来框架的事件分发机制中就会被访问到了。
当然Listener的添加入口也有两个对应的函数:
void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);
void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);
通过函数声明可以看到add SceneGraphPriority的时候要传递node这时候Listener会被添加到SceneGraph的队列
add FixedPriority同理
当然
EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);
这个函数还提供了第三种添加过程,估计是可以添加一些用户自定义事件来达到不同层的事件传递吧,这里还没有研究。
这里主要说说事件的分发机制:
首先事件通过cocos2dx的EventDispatcher中的dispatchEvent函数来传递,
传递主要针对上述两个ListenerVector
首先是对fixedListener 和 sceneGraphListener进行排序(fixedListeners按照fixedPriority从小到大的顺序进行排序,sceneGraphListeners按照priority由大到小排序,这里估计是按照显示层级来排序了)
其次,对排序后的两个listeners 数组进行事件传递,传递的原则是首先把事件传递到fixedLisener中优先级<0的Lisener中,如果事件被处理则break终止传递,如果不被处理则传递到sceneListener中,同理不被处理继续传递到fixedListener中优先级>0的Listener中,直到事件被处理或者被丢弃(没有任何节点处理)。
至此完成了一个事件传递过程。上述scrollview添加到layer的问题也就有了解决方案:
直接把listener添加到fixedpriority中然后设置优先级为一个较小的数如-1000即可。
更加详细的事件分发细节,还没有来得及研究,不过大的框架和流程就是这样,可以先用着了。
原文链接:http://hi.baidu.com/baihebeijixing/item/674b8bc00548f70f0ad93af8