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

  

 

posted @   、拂晓  阅读(1175)  评论(1编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示