关于cocos2d-x中CCScrollView和CCMenu触摸优先级的解决方案

来源:互联网 发布:网络销售总结报告 编辑:程序博客网 时间:2024/05/07 01:29

一,

最近使用cocos2d-x写一款跨平台的游戏,有这样一个功能需求,手机屏幕的某块区域可上下滚动,滚动区域的内容又是可点击的按钮。首先想到在CCScrollView里面添加CCMenu。恰好这个CCMenu是一张张图片,即CCItemImage,当图片布满整个滚动区域的时候,你会发现CCScrollView滑动不了了。原因很简单,是CCMenu的触摸事件吃掉了CCScrollView的触摸事件,因为CCMenu的默认触摸优先级是最高的。于是就有两套解决方案,一是改变CCScrollView的优先级,使之比CCMenu还高,CCMenu的默认优先级是-128,CCScrollView的默认优先级是0,cocos2d-x中数值越低,优先级越高。二是改变CCMenu的优先级,使之比CCScrollView低就行了。

  接下来如何改还是个问题,我们知道CCMenu和CCScrollView都是继承CCLayer的,CCLayer有一个虚方法registerWithTouchDispatcher,在此方法中用如下代码CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, kCCMenuTouchPriority, true);控制此Layer的优先级。而CCMenu和CCScrollView都复写了此方法。我们只需要在复写的方法中修改优先级就可以了。我们最好不要改动cocos2d的源码,所以我们可以写一个自己的menu来继承CCMenu,并复写registerWithTouchDispatcher方法,代码如下:

1 class MyMenu : public CCMenu{2     virtual void registerWithTouchDispatcher(){3         //这里优先级设为1,只要比CCScrollView低就可以4         CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 1, true);5     }6 }

接下来用MyMenu替换原来的CCMenu就行了,这样它会先响应CCScrollView的滑动,再响应CCMenu的点击。


二,

上次说到CCScrollView里面添加CCMenu可以解决触摸优先级的问题,但实际上还有问题,滑动是可以滑动了,但滑动一松手,它可能立马响应CCMenu的点击事件,还有,当CCMenu超出可视区域后还是能够点击,这也是让人头疼的问题。问题虽然让人头疼,但解决方案还是有的。我们还是从上篇的CCMenu的扩展类MyMenu入手,我给MyMenu添加moved属性,初始化为false,在ccTouchMove事件里赋值为true,最后在ccTouchEnd里面判断是否move,如果move就不调用CCMenu的ccTouchEnd。这里要注意两点,一是每次ccTouchBegan的时候都要将move设为false,还有ccTouchEnd里面当move为true时,继承CCMenu的属性m_eState要设为kCCMenuStateWaiting,否则它就会在ccTouchBegan的时候return false而进不到ccTouchEnd中了。具体代码:

复制代码
 1 bool MyMenu::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){     2     if(visibleRect_.size.width&&visibleRect_.size.height){ 3         if(!visibleRect_.containsPoint(pTouch->getLocation())) 4             return false; 5     } 6     moved_=false; 7     return CCMenu::ccTouchBegan(pTouch,pEvent); 8 } 9 10 void MyMenu::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){11     moved_=true;12     CCMenu::ccTouchMoved(pTouch,pEvent);13 }14 15 void MyMenu::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){16     if(!moved_)17         CCMenu::ccTouchEnded(pTouch,pEvent);18     else19         m_eState = kCCMenuStateWaiting;20 }
复制代码

大家发现ccTouchBegan里面多了visibleRect_几行代码,这个就是用来判断CCMenu是否在可视区域,当不在可视区域直接return false,这样在超出可视区域点击CCMenu是无效的。当然这个可视区域是具体使用的地方传入的,其实也就是scrollView的viewSize。好啦,至此关于CCScrollView中添加CCMenu造成的一系列问题都得以解决。