zoukankan      html  css  js  c++  java
  • 解决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工作量小多了、、、

    // 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;
    };
    

      

    //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。

    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();
    		}
    	}
    }
    

      

    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;
    }
    

      

     

  • 相关阅读:
    第2章 类模板:2.3 类模板的局部使用
    第2章 类模板:2.2 类模板Stack的使用
    第2章 类模板:2.1 类模板Stack的实现
    第1章 函数模板:1.6 但是,我们不应该…?
    第1章 函数模板:1.5 重载函数模板
    第1章 函数模板:1.4 默认模板参数
    第1章 函数模板:1.3 多模板参数
    第1章 函数模板:1.2 模板参数的推导
    第1章 函数模板:1.1 初识函数模板
    第31课 std::atomic原子变量
  • 原文地址:https://www.cnblogs.com/songcf/p/3616052.html
Copyright © 2011-2022 走看看