解决TableView / ScrollView上的Menu问题(1滑出View区域还可点击2导致点击menu后View不能滑动)
解决TableView / ScrollView上的Menu问题
1划出区域还可点击
重写CCMenu的触摸事件函数 TouchBegin/TouchMove/TouchCancle/TouchEnd
如果点击超出了 TableView/ScrollView边界则 TouchBegin返回false
2导致View不能滑动
透传CCMenu的触摸吞噬、让触摸可以下传,然后再touchMove中增加一个触摸滑动校验、如果触摸移动大于某个值(比如16),那么CCMenu则丢弃该触摸、不让menuItem执行activate,那么滑动的时候view上的menu就不会响应了。
也可以自己写个新的view,把里面的menu换成sprite,自己判断点击的位置,然后就知道点击的是哪一个了。相比之下重写menu工作量小多了、、、
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 | // FXScrollMenu.h #pragma once #include "cocos2d.h" using namespace cocos2d; class FXScrollMenu : public cocos2d::CCMenu { public : //scrollVeiw/tabelView左下角世界坐标,view大小,menu超过view边界的部分就不可点击 //menu不会吞噬触摸消息,滑动时不响应消息 static FXScrollMenu* create(cocos2d::CCPoint viewLeftDownPos_worldCoordinate, cocos2d::CCSize viewAreaSize); bool init(cocos2d::CCPoint viewLeftDownPos_worldCoordinate, cocos2d::CCSize viewAreaSize); virtual void registerWithTouchDispatcher(); /** @brief For phone event handle functions */ virtual bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event); virtual void ccTouchEnded(cocos2d::CCTouch* touch, cocos2d::CCEvent* event); virtual void ccTouchCancelled(cocos2d::CCTouch *touch, cocos2d::CCEvent* event); virtual void ccTouchMoved(cocos2d::CCTouch* touch, cocos2d::CCEvent* event); protected : CCSize mViewSize; CCPoint mViewLeftDownPos; CCRect mViewRect; CCPoint mTouchStartPos; bool mTouchMoved; }; |
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | //FXScrollMenu.cpp #include "FXScrollMenu.h" //(点击校验范围) #define ViewTouchMove_Delta 16 FXScrollMenu* FXScrollMenu::create(cocos2d::CCPoint viewLeftDownPos_worldCoordinate, cocos2d::CCSize viewAreaSize) { FXScrollMenu *menu = new FXScrollMenu; if (menu && menu->init(viewLeftDownPos_worldCoordinate, viewAreaSize)) { menu->autorelease(); } else { CC_SAFE_DELETE(menu); menu = NULL; } return menu; } bool FXScrollMenu::init(cocos2d::CCPoint viewLeftDownPos_worldCoordinate, cocos2d::CCSize viewAreaSize) { if ( ! CCMenu::init()) return false ; mViewLeftDownPos = viewLeftDownPos_worldCoordinate; mViewSize = viewAreaSize; mViewRect.setRect(mViewLeftDownPos.x, mViewLeftDownPos.y, mViewSize.width, mViewSize.height); return true ; } void FXScrollMenu::registerWithTouchDispatcher() { CCDirector* pDirector = CCDirector::sharedDirector(); pDirector->getTouchDispatcher()->addTargetedDelegate( this , this ->getTouchPriority(), false ); } bool FXScrollMenu::ccTouchBegan(CCTouch* touch, CCEvent* event) { CCLog( "FXScrollMenu : %s " , __FUNCTION__); CC_UNUSED_PARAM(event); // if (m_eState != kCCMenuStateWaiting || ! m_bVisible || !m_bEnabled) //by fx if (m_eState != kCCMenuStateWaiting || ! m_bVisible || ! isEnabled()) { return false ; } for (CCNode *c = this ->m_pParent; c != NULL; c = c->getParent()) { if (c->isVisible() == false ) { return false ; } } mTouchStartPos = touch->getLocation(); // by fx add if (mViewRect.containsPoint(mTouchStartPos)) // by fx add { mTouchMoved = false ; // by fx add m_pSelectedItem = this ->itemForTouch(touch); if (m_pSelectedItem) { m_eState = kCCMenuStateTrackingTouch; m_pSelectedItem->selected(); return true ; } } return false ; } void FXScrollMenu::ccTouchMoved(CCTouch* touch, CCEvent* event) { // if (mTouchMoved) return ; // CC_UNUSED_PARAM(event); CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchMoved] -- invalid state" ); CCMenuItem *currentItem = this ->itemForTouch(touch); //add //移动了、那么该按钮不再响应点击消息了 CCPoint movePos = touch->getLocation(); if ( fabs (movePos.x - mTouchStartPos.x) > ViewTouchMove_Delta || fabs (movePos.y - mTouchStartPos.y) > ViewTouchMove_Delta) { if (m_pSelectedItem) { m_pSelectedItem->unselected(); } mTouchMoved = true ; return ; } // if (currentItem != m_pSelectedItem) { if (m_pSelectedItem) { m_pSelectedItem->unselected(); } m_pSelectedItem = currentItem; if (m_pSelectedItem) { m_pSelectedItem->selected(); } } } void FXScrollMenu::ccTouchEnded(CCTouch *touch, CCEvent* event) { CC_UNUSED_PARAM(touch); CC_UNUSED_PARAM(event); CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchEnded] -- invalid state" ); // if (m_pSelectedItem) if (m_pSelectedItem && ! mTouchMoved) { m_pSelectedItem->unselected(); m_pSelectedItem->activate(); } m_eState = kCCMenuStateWaiting; } void FXScrollMenu::ccTouchCancelled(CCTouch *touch, CCEvent* event) { CC_UNUSED_PARAM(touch); CC_UNUSED_PARAM(event); CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchCancelled] -- invalid state" ); // if (m_pSelectedItem) if (m_pSelectedItem && ! mTouchMoved) { m_pSelectedItem->unselected(); } m_eState = kCCMenuStateWaiting; } |
——————————————————————————————————————————
华丽的分割线
——————————————————————————————————————————
FXScrollMenu注册触摸消息时,设置的是不吞噬触摸,那么在点击按钮后,按钮响应了消息,如果TableCell也会相应touch消息,那么会触发两个事件,但此时我不希望tableCell也被触发,所以最好还是把FXScrollMenu注册为吞噬触摸。
那么此时如果只是想滑动界面,却点击到了menu不就滑不动了么,--->解决方法:在touchMove中校验得知是滑动view后,将该CCTouch保存下来,并发送出去CCDirector::sharedDirector()->getTouchDispatcher()->touchesBegan()(祥见另外一篇博文:触摸派发原理),然后在FXScrollMenu的touchBegan中判断如果是保存的menu则return false。
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 57 58 59 60 | void FXScrollMenu::ccTouchMoved(CCTouch* touch, CCEvent* event) { // if (mTouchMoved) return ; // CC_UNUSED_PARAM(event); CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchMoved] -- invalid state" ); CCMenuItem *currentItem = this ->itemForTouch(touch); //add //移动了、那么该按钮不再响应点击消息了 CCPoint movePos = touch->getLocation(); if ( fabs (movePos.x - mTouchStartPos.x) > ViewTouchMove_Delta || fabs (movePos.y - mTouchStartPos.y) > ViewTouchMove_Delta) { if (m_pSelectedItem) { m_pSelectedItem->unselected(); } mTouchMoved = true ; CCTargetedTouchHandler* pHandler = dynamic_cast <CCTargetedTouchHandler*>( CCDirector::sharedDirector()->getTouchDispatcher()->findHandler( this )); if (pHandler) { //把自己的touch移除、避免后面响应touchMove CCSet* mySet = pHandler->getClaimedTouches(); mySet->removeObject(touch); m_eState = kCCMenuStateWaiting; //然后重新派发出一个 触摸消息给低优先级的(该touch已被吞噬) mpTouch = touch; CCSet* _set = CCSet::create(); _set->addObject(mpTouch); CCDirector::sharedDirector()->getTouchDispatcher()->touchesBegan(_set, NULL); } return ; } // if (currentItem != m_pSelectedItem) { if (m_pSelectedItem) { m_pSelectedItem->unselected(); } m_pSelectedItem = currentItem; if (m_pSelectedItem) { m_pSelectedItem->selected(); } } } |
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 | bool FXScrollMenu::ccTouchBegan(CCTouch* touch, CCEvent* event) { //是否是重新派发的 if (touch == mpTouch) { mpTouch = NULL; return false ; } // CCLog("FXScrollMenu : %s ", __FUNCTION__); CC_UNUSED_PARAM(event); // if (m_eState != kCCMenuStateWaiting || ! m_bVisible || !m_bEnabled) //by fx if (m_eState != kCCMenuStateWaiting || ! m_bVisible || ! isEnabled()) { return false ; } for (CCNode *c = this ->m_pParent; c != NULL; c = c->getParent()) { if (c->isVisible() == false ) { return false ; } } mTouchStartPos = touch->getLocation(); // by fx add if (mViewRect.containsPoint(mTouchStartPos)) // by fx add { mTouchMoved = false ; // by fx add m_pSelectedItem = this ->itemForTouch(touch); if (m_pSelectedItem) { m_eState = kCCMenuStateTrackingTouch; m_pSelectedItem->selected(); return true ; } } return false ; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步