关于cocostudio动态添加控件触摸响应无效的学习

time:2015/04/19

1. 描述

  * 自己也碰到了在cocostudio上碰到点击按钮没有响应的情况

  * 另外,网上有朋友也碰到过,所以自己觉得按照3.0的cocos引擎的新渲染逻辑应该是可以设置的

2. 学习

(1)代码直接调试

动态添加一个按钮或者一个精灵到有cocostudio加载的layout

* 按钮和layout在一个层级,都加载layer上,没有位置上的重叠:结果没有影响,两遍都能响应触摸事件

* 按钮和layout在一个层级,都加载layer上,有位置上的重叠:结果依旧没有影响

* 按钮在layout之前addchild:直接看不见了

* 按钮在layout之后addchild:没有影响

* 按钮属于layout,layout:addChild(),没有位置上的重叠:结果没有影响

* 按钮属于layout,layout:addChild(),有位置上的重叠:结果没有影响

* 添加一个精灵,自己添加触摸事件:

Sprite* sprite = Sprite::create("cocosui/green_edit.png");
bgd->addChild(sprite, 0);
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(UIButtonTest_Editor::onTouchBegan, this);
listener->onTouchEnded = CC_CALLBACK_2(UIButtonTest_Editor::onTouchEnded, this);
 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

  1)localZorder默认为0

    * 有影响,具体表现为:点击layout上的按钮有响应;点击精灵sprite也有响应;点击除了layout上的按钮之外所有的地方,包括layout内以及外的点都会响应sprite

    * 为什么?因为默认的Button做了区域检测,点击按钮之外不响应;但是自己上面定义的精灵没有做处理,所以原则上会接受到任何触摸的消息

    * 点击layout上的按钮的时候,sprite其实是没有接受到触摸消息的,说明什么?第一,layout上的按钮把消息吞掉了;第二,layout上的按钮先于sprite接受到触摸消息

  -->关于说明的第一点,看源码: [_touchListener->setSwallowTouches(true);]

void Widget::setTouchEnabled(bool enable)
{
    if (enable == _touchEnabled)
    {
        return;
    }
    _touchEnabled = enable;
    if (_touchEnabled)
    {
        _touchListener = EventListenerTouchOneByOne::create();
        CC_SAFE_RETAIN(_touchListener);
        _touchListener->setSwallowTouches(true);
        _touchListener->onTouchBegan = CC_CALLBACK_2(Widget::onTouchBegan, this);
        _touchListener->onTouchMoved = CC_CALLBACK_2(Widget::onTouchMoved, this);
        _touchListener->onTouchEnded = CC_CALLBACK_2(Widget::onTouchEnded, this);
        _touchListener->onTouchCancelled = CC_CALLBACK_2(Widget::onTouchCancelled, this);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
    }
    else
    {
        _eventDispatcher->removeEventListener(_touchListener);
        CC_SAFE_RELEASE_NULL(_touchListener);
    }
}

  -->关于第二点看后面的分享-->

  2)localZorder为1,bgd->addChild(sprite, 1)

    * 同1)

  3)sprite的localZOrder为-1

    * 同1)

  4)sprite->setGlobalZorder(1)

    * 同1)

(2)cocos的事件处理顺序

* 看两个接口大致可以看到,处理顺序有优先级之分: <0, 0, >0

addEventListenerWithSceneGraphPriority: 默认为0
addEventListenerWithFixedPriority: 有正负之分了

* 优先级判断的逻辑

void EventDispatcher::sortEventListeners(const EventListener::ListenerID& listenerID)
{
    DirtyFlag dirtyFlag = DirtyFlag::NONE;

    auto dirtyIter = _priorityDirtyFlagMap.find(listenerID);
    if (dirtyIter != _priorityDirtyFlagMap.end())
    {
        dirtyFlag = dirtyIter->second;
    }

    if (dirtyFlag != DirtyFlag::NONE)
    {
        // Clear the dirty flag first, if `rootNode` is nullptr, then set its dirty flag of scene graph priority
        dirtyIter->second = DirtyFlag::NONE;

        if ((int)dirtyFlag & (int)DirtyFlag::FIXED_PRIORITY)
        {       //自定义优先级排序
            sortEventListenersOfFixedPriority(listenerID);
        }

        if ((int)dirtyFlag & (int)DirtyFlag::SCENE_GRAPH_PRIORITY)
        {
            auto rootNode = Director::getInstance()->getRunningScene();
            if (rootNode)
            {          //默认优先级为0的排序
                sortEventListenersOfSceneGraphPriority(listenerID, rootNode);
            }
            else
            {
                dirtyIter->second = DirtyFlag::SCENE_GRAPH_PRIORITY;
            }
        }
    }
}

  -->自定义优先级没什么好说的,看排序算法就知道了,按自定义的数值排序;

  -->如果相同就按照开始插入的顺序继续,排序算法是不是稳定的还要再看

* 默认为0的优先级排序

visitTarget(rootNode, true);

    // After sort: priority < 0, > 0
    std::sort(sceneGraphListeners->begin(), sceneGraphListeners->end(), [this](const EventListener* l1, const EventListener* l2) {
        return _nodePriorityMap[l1->getAssociatedNode()] > _nodePriorityMap[l2->getAssociatedNode()];
    });

  -->这里的排序算法已经不同于自定义的排序算法了,一眼看上去不明觉厉

  -->所以要看上面的一个函数,visitTarget,就是这个函数中构造_nodePriorityMap结构的

  -->仔细看visitTarget函数其实就是cocos3.0以上的一个渲染顺序的逻辑:globalZorder和globalZorder两个共同决定了渲染顺序,globalZorder高于localZorder,这同时也决定了这个渲染顺序可以让不同的layer上的node有不同的渲染顺序,而且跟parent的layer层级关系没有关系(是这样理解的,但是没有去验证!)  

  -->总结就是:这里的优先级是先看节点的globalZorder,再看localZorder,如果相同就按照默认加入的顺序。即,先加入的先渲染,先处理事件

3. 问题

  从上面的理解来看,cocostudio的按钮在最底层,所以会先接受到触摸消息,并且吞掉,从而其他控件(自定义的)不能接受到触摸消息;但是,自己即使设置了自定义的sprite,还是在studio的按钮之后接收到触摸消息,结果是如果点击的是按钮,自定义控件不会响应!

4. 参考:

[1] http://www.it165.net/pro/html/201405/13283.html

时间: 2024-10-25 02:14:55

关于cocostudio动态添加控件触摸响应无效的学习的相关文章

winform导入导出excel,后台动态添加控件

思路: 导入: 1,初始化一个OpenFileDialog类 (OpenFileDialog fileDialog = new OpenFileDialog();) 2, 获取用户选择文件的后缀名(string extension = Path.GetExtension(fileDialog.FileName).ToLower();),并设置允许后缀文件名: 3,NPOI转datetable,遍历tatetable转成实体类列表并入库: 导出: 1, 创建提示用户保存类,SaveFileDial

android 在布局中动态添加控件

第一步 Java代码 final LayoutInflater inflater = LayoutInflater.from(this); 第二步:获取需要被添加控件的布局 Java代码 final LinearLayout lin = (LinearLayout) findViewById(R.id.LinearLayout01); 第三步:获取需要添加的布局(控件) Java代码 LinearLayout layout = (LinearLayout) inflater.inflate( R

New UI-Java代码动态添加控件或xml布局

New UI-Java代码动态添加控件或xml布局  --转载请注明出处:coder-pig,欢迎转载,请勿用于商业用途! 小猪Android开发交流群已建立,欢迎大家加入,无论是新手,菜鸟,大神都可以,小猪一个人的 力量毕竟是有限的,写出来的东西肯定会有很多纰漏不足,欢迎大家指出,集思广益,让小猪的博文 更加的详尽,帮到更多的人,O(∩_∩)O谢谢! 小猪Android开发交流群:小猪Android开发交流群群号:421858269 新Android UI实例大全目录:http://blog.

Android 在布局容器中动态添加控件

这里,通过一个小demo,就可以掌握在布局容器中动态添加控件,以动态添加Button控件为例,添加其他控件同样道理. 1.addView 添加控件到布局容器 2.removeView 在布局容器中删掉已有的控件 3.使用,来个小demo就明白了 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(save

android 动态添加控件并实现每个子控件的点击事件

需求:我们要点击进入一家店铺,根据不同的店铺,显示不同条数的子条目 如:消毒间,洗菜间等...这些都是或多或少的,所以需要动态添加: 首先自定义View(linearLayout): package cn.qust.fang.widget; import io.vov.vitamio.MediaPlayer; import io.vov.vitamio.widget.MediaController; import io.vov.vitamio.widget.VideoView; import a

C#动态添加控件到窗体不显示

在FormLoad里面添加控件时,用this.Controls.Add()方法向窗体里面动态添加控件,调试,一直不显示,后来发现原来窗体上有一个groupbox覆盖了整个窗体,其实控件已经添加上去了,只是被遮盖了. 后面改为this.groupBox1.Controls.Add(),把控件添加到groupbox里面就不会被遮盖了 1 private void UniqueForm_Load(object sender, EventArgs e) 2 { 3 if (pFlag == 1) 4 {

DevExpress.XtraLayout.LayoutControl 动态添加控件

// Create an item within a specified group,// bound to a specified data field with the specified editorprivate LayoutControlItem CreateItemWithBoundEditor(BaseEdit editor, object dataSource,   string dataMember, LayoutControlGroup parentGroup) {   ed

asp.net动态添加控件学习

看了老师的教程后,自己一点感悟记录下来: 1.在页面提交后,动态生成的控件会丢失, 但如果生成控件的代码在pageload中,就可以,原理是每次生成页面都执行生成. 2.动态按件或页面原来控件, 在页面往返重新生成时, 都有一个特点.就是控件里面的值和状态会保留下来. 如: 在DorpDownList中动态添加了 item项, 在页面往返后, 这个项是保留下来的, 选中值selected也是保留下来的. 在CheckBox中的值,或是动态添加的CheckBox中的值,页面返回后,其中的check

WPF 动态添加控件以及样式字典的引用(Style introduction)

原文:WPF 动态添加控件以及样式字典的引用(Style introduction) 我们想要达到的结果是,绑定多个Checkbox然后我们还可以获取它是否被选中,其实很简单,我们只要找到那几个关键的对象就可以了. 下面是Ui,其中定义了一个WrapPanel来存放CheckBox,还有两个按钮,用于测试相关功能. <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.c