zoukankan      html  css  js  c++  java
  • cocos2d-x中false,setSwallowTouches,stopPropagation的区别

    研究到cocos2d-x触摸这一块了,3.0和2.0相比已经有了很大的不同,使用更加方便和容易理解了。

    直接进入正题,解释下,标题中3个用法的区别

    通常来说,应用程序中更多使用的是单点触摸,为了简化单点触摸的处理,cocos2dx将一个触摸事件分为单点触摸和多点触摸两种类型,相应的对应单点和多点两种订阅者类型

     EventListenerTouchAllAtOnce分为四种状态,开始触摸,移动,结束,取消,

    每一个状态的回调函数都包含当前所有处于该种状态的触摸点,开发者需要使用触摸点的ID来区分每一个触摸点

    EventListenerTouchOneByOne则相反,他将触摸某个状态的多个触摸点分为多次事件通知 ,他也分为四种状态,开始触摸,移动,结束,取消。

    不同的地方是他的开始触摸方法 onTouchBegan返回值为bool,并且onTouchBegan是必须实现的,否则将收不到任何触摸事件通知,而EventListenerTouchAllAtOnce的onTouchBegan没有返回值,他的实现与否不影响后续状态的回调

    下面就牵扯到了返回true与false的问题。

    onTouchBegan的返回值用来告诉EventDispatcher是否应该讲触摸点后续的触摸状态传递给订阅者。如果为false,onTouchMoved

    onTouchEnded和onTouchCancelled,将接受不到任何回调。

    但是注意的是,这个返回值只对当前订阅者有效,对后续订阅者的回调是控制不了的。比如

    Node A 订阅了 EventListenerTouchOneByOne和 EventListenerTouchAllAtOnce两种触摸类型,前者的onTouchBegan返回false,那么当点击了NodeA的时候(就是一点一抬,不涉及移动),触发了点击事件,那么执行的顺序为这个

     1 EventListenerTouchOneByOne:onTouchBegan

     2EventListenerTouchAllAtOnce:onTouchBegan

     3EventListenerTouchAllAtOnce:onTouchEnd,

    说明false只控制了EventListenerTouchOneByOne类型的订阅,对于Node订阅的EventListenerTouchAllAtOnce类型,控制不了,该怎么走还是怎么走。

    再比如:

    NodeA订阅了EventListenerTouchOneByOne,NodeB也订阅了EventListenerTouchOneByOne,并且NodeA的localZ小于NodeB的localZ,NodeA的onTouchBegan返回false,NodeB的onTouchBegan返回true,当触发点击事件之后,执行顺序为

     1  NodeA  EventListenerTouchOneByOne:onTouchBegan

     2  NodeB  EventListenerTouchOneByOne:onTouchBegan

     3 NodeB  EventListenerTouchOneByOne:onTouchEnd

    说明NodeA的false只对订阅者nodeA起作用,对NodeB不起作用

    这就是false的用法,如果想让当前订阅者继续往后面的状态传递,就返回true,不想让其传递,就返回false。

    这种情况一般用在比如你点击了屏幕,但是坐标并没有落在某个sprite的可显示区域的上面,那么就返回false,反之返回true。比如下面得代码

    bool isPointInNode(Vec2 pt, Node* node)
    
    {
    
        Vec2 locationInNode = node->convertToNodeSpace(pt);
    
       cocos2d::Size s = node->getContentSize();
    
        cocos2d::Rect rect = cocos2d::Rect(0, 0, s.width, s.height);
    
        
    
        if (rect.containsPoint(locationInNode))
    
        {
    
            return true;
    
        }
    
        return false;
    
    }
    
     
    
           touchOneByOneListener->onTouchBegan = [&](Touch* touch, Event* event){
    
      auto target = static_cast<Sprite*>(event->getCurrentTarget());
    
                    if (this->isPointInNode(touch->getLocation(), target))
    
                    {
    
                        target->setOpacity(180);
    
                        return true;
    
                    }
    
       return false;
    
              };

     下面再说说setSwallowTouches的作用

    当我们希望阻止一个触摸点向后面的订阅者继续分发,那么可以使用setSwallowTouches(true)来实现。

    注意,swallowTouches设置需要在onTouchBegan返回true的时候才有效.

    例如Sprite 和Sprite2都加到了同一个Node上,SpriteA后加,也就是SpriteA会先收到触摸事件,他们都订阅了EventListenerTouchOneByOne和

    EventListenerTouchAllAtOnce

    ,如下代码

    static const int TAG_BLUE_SPRITE = 101;
        static const int TAG_BLUE_SPRITE2 = 102;
        
        auto touchOneByOneListener = EventListenerTouchOneByOne::create();
         touchOneByOneListener->setSwallowTouches(true);
        
        touchOneByOneListener->onTouchBegan = [&](Touch* touch, Event* event){
            
       
        return true;
       
        };
        
        touchOneByOneListener->onTouchEnded = [](Touch* touch, Event* event){
            auto target = static_cast<Sprite*>(event->getCurrentTarget());
            target->setOpacity(255);
            
        };
        
        
        auto touchAllAtOnceListener = EventListenerTouchAllAtOnce::create();
        touchAllAtOnceListener->onTouchesBegan = [=](const std::vector<Touch*>& touches, Event* event){
            
            
               };
        
        touchAllAtOnceListener->onTouchesEnded = [=](const std::vector<Touch*>& touches, Event* event){
            
               };
        
        
        
        Sprite* sprite;
        Sprite* sprite2;
        
        sprite = Sprite::create("CyanSquare.png");
        sprite->setTag(TAG_BLUE_SPRITE);
        addChild(sprite, 100);
        
        sprite2 = Sprite::create("YellowSquare.png");
        sprite2->setTag(TAG_BLUE_SPRITE2);
        addChild(sprite2, 100);
        
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchOneByOneListener->clone(), sprite);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchAllAtOnceListener->clone(), sprite);
        
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchOneByOneListener->clone(), sprite2);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchAllAtOnceListener->clone(), sprite2);
        
        sprite->setPosition(100,200);
        sprite2->setPosition(50,200);

    注意我们设置 touchOneByOneListener->setSwallowTouches(true);

    默认是false,通过设置了true,那么就可以阻止一个触摸点继续向后面的订阅者继续分发,

    当点击事件触发后,执行顺序如下

     1 spriteA  touchOneByOneListener->onTouchBegan

     2  spriteA  touchOneByOneListener->onTouchEnd

    因为spriteA的touchOneByOneListener->setSwallowTouches(true);他会阻止此后所有事件的分发,无论是spriteA自己的订阅类型EventListenerTouchAllAtOnce以及SpriteB的所有订阅类型。

    这里说的一个应用的地方比如,spriteA订阅了单点触摸和多点触摸,但是他只想进行单点触摸的回调,而不想进行多点触摸的回调,那么就可以设置ontouchbegin返回true,并设置setSwallowTouches(true),这样就可以阻止多点触摸事件的分发。

     

    最后说的是stopPropagation,他和setSwallowTouches类似,也是阻止触摸点后面订阅者的事件分发,但是不同的是setSwallowTouches阻止的很彻底,他会阻止后面所有状态的分发,began,end,cancelled,moved,并且必须ontouchbegan返回true才会起作用,而stopPropagation只是阻止某个状态的分发,比如move状态等。

    stopPropagation只是停止当前当次触摸状态下的所有分发,例如Moved状态会触发多次,则第二次不受前一次的影响。某个状态也不会影响另一个状态的分发,例如move不影响end状态的分发,所有这些只需要明白,每个状态每次分发都是一次独立的事件通知

    举例子如下:

    static const int TAG_BLUE_SPRITE = 101;
        static const int TAG_BLUE_SPRITE2 = 102;
        
        auto touchOneByOneListener = EventListenerTouchOneByOne::create();
         touchOneByOneListener->setSwallowTouches(false);
        
        touchOneByOneListener->onTouchBegan = [&](Touch* touch, Event* event){
            
            auto target = static_cast<Sprite*>(event->getCurrentTarget());
           if(target->getTag() == TAG_BLUE_SPRITE2)
           {
               printf("sprite2单点触摸--ontouchbegan
    ");
           }
           else{
                printf("sprite单点触摸--ontouchbegan
    ");
           }
           // event->stopPropagation();
          return true;
       
        };
        
        touchOneByOneListener->onTouchEnded = [](Touch* touch, Event* event){
            auto target = static_cast<Sprite*>(event->getCurrentTarget());
            if(target->getTag() == TAG_BLUE_SPRITE2)
            {
                printf("sprite2单点触摸--ontouchend
    ");
            }
            else{
                printf("sprite单点触摸--ontouchend
    ");
            }
    
            
        };
        
        
        auto touchAllAtOnceListener = EventListenerTouchAllAtOnce::create();
        touchAllAtOnceListener->onTouchesBegan = [=](const std::vector<Touch*>& touches, Event* event){
            
            auto target = static_cast<Sprite*>(event->getCurrentTarget());
            if(target->getTag() == TAG_BLUE_SPRITE2)
            {
                printf("sprite2多点触摸--ontouchbegan
    ");
            }
            else{
                printf("sprite多点触摸--ontouchbegan
    ");
            }
    
            
        };
        
        touchAllAtOnceListener->onTouchesEnded = [=](const std::vector<Touch*>& touches, Event* event){
            auto target = static_cast<Sprite*>(event->getCurrentTarget());
            if(target->getTag() == TAG_BLUE_SPRITE2)
            {
                printf("sprite2多点触摸--ontouchend
    ");
            }
            else{
                printf("sprite多点触摸--ontouchend
    ");
            }
       
         
        };
        
        
        
        Sprite* sprite;
        Sprite* sprite2;
        
        sprite = Sprite::create("CyanSquare.png");
        sprite->setTag(TAG_BLUE_SPRITE);
        addChild(sprite, 100);
        
        sprite2 = Sprite::create("YellowSquare.png");
        sprite2->setTag(TAG_BLUE_SPRITE2);
        addChild(sprite2, 100);
        
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchOneByOneListener->clone(), sprite);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchAllAtOnceListener->clone(), sprite);
        
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchOneByOneListener->clone(), sprite2);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(touchAllAtOnceListener->clone(), sprite2);
        
        sprite->setPosition(100,200);
        sprite2->setPosition(50,200);

    执行代码结果如下

    sprite2单点触摸--ontouchbegan

    sprite单点触摸--ontouchbegan

    sprite2多点触摸--ontouchbegan

    sprite多点触摸--ontouchbegan

    sprite2单点触摸--ontouchend

    sprite单点触摸--ontouchend

    sprite2多点触摸--ontouchend

    sprite多点触摸--ontouchend

    这个结果很容易理解,就是没有阻止事件的分发,一切都是按计划进行

    如果 event->stopPropagation()的注释去掉,那么执行结果如下:

    sprite2单点触摸--ontouchbegan

    sprite2单点触摸--ontouchend

    sprite2多点触摸--ontouchend

    sprite多点触摸--ontouchend

     这个的解释为:

    sprite2的touchbegan先回调,然后stopprpagation,之后关于touchbegan的状态的事件分发就会停止,也就是sprite的touchbegan不会执行了,

    而sprite的单点触摸的touchbegan不执行,那么sprite的单点触摸的其余状态也不会执行,但是sprite的多点触摸的touchbegan不执行,不影响多点触摸的其他状态的执行,所以sprite就执行了一个多点触摸的ontouchend

     

    以上就是对这三种用法的简单解释,如果需要查看其工作原理,还是要深入到源码中,进行了解。

     

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    plt.annotate() 在图中标注文字
    numpy 的 ravel() 和 flatten() 扁平化函数
    springboot 国际化
    springboot 日志
    springboot render 和 重定向
    将jar包 引入到maven
    requests 上传图片加额外参数
    java 占位符
    springboot JSR303 后端数据校验
    Python入门学习笔记10:函数式编程:匿名函数、高阶函数、装饰器
  • 原文地址:https://www.cnblogs.com/xiaonanxia/p/4861282.html
Copyright © 2011-2022 走看看