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

  

解决TableView / ScrollView上的Menu问题(1滑出View区域还可点击2导致点击menu后View不能滑动)的更多相关文章

  1. 解决iscroll.js上拉下拉刷新手指划出屏幕页面无法回弹问题

    博客已迁移至http://zlwis.me. 使用过iscroll.js的上拉下拉刷新效果的朋友应该都碰到过这个问题:在iOS的浏览器中,上拉或下拉刷新时,当手指划出屏幕后,页面无法弹回.很多人因为解 ...

  2. 解决tableView中cell动态加载控件的重用问题

    解决tableView中cell动态加载控件的重用问题 tableView的cell,有时候需要在运行时取得对应的数据后才能够动态的创建该cell中的控件并加载到该cell中,此时,你一定会遇到重用问 ...

  3. iOS Autolayout 在tableView scrollView 适用 学习

    1  如何自动适应cell的高度 autolayout  里面 使用 systemLayoutSizeFittingSize 方法 (系统通过 已知的完整的Constraints和view的属性来计算 ...

  4. 禁止tableview 像上滑动

    tableView有一个bounces属性.默认YES,所以tableView上下用力拉都会有弹性滑动,如下设置可以禁止,但是这样的话上下弹性都没了 而经常的需求是上方不要弹性,下方要弹性,可以用监听 ...

  5. 当cell中有UItextfiled或者UITextVIew时,弹出键盘把tableview往上,但是有的cell没有移动

    cell中有UITextView时,输入文字是需要将tableView向上移,基本的做法是,注册键盘变化的通知在通知的方法中做tableVIew的位置调整, 一,一般做法 - (void)regist ...

  6. IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法IIS上部署MVC网站,打开后500错误

    IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法 IIS上部署MVC网站,打开后500错误:处理程序“ExtensionlessUrl ...

  7. Gulp解决发布线上文件(CSS和JS)缓存问题

    Gulp解决发布线上文件(CSS和JS)缓存问题 本文的缘由:目前经常线上发布文件后要不断的刷新页面及过很长时间,页面上的CSS和JS文件才能生效,特别对于目前做微信商城的时候,微信内置的浏览器缓存非 ...

  8. 自定义plain 样式的 tableview,模拟器上不显示分割线,真机上却显示分割线.

    一, 经历 1> 自定义plain 样式的 tableview,模拟器上不显示分割线,真机上却显示cell 下面的分割线. 2> 尝试使用表格的separatorStyle属性,尝试失败. ...

  9. 微信JSSDK多图片上传并且解决IOS系统上传一直加载的问题

    微信多图片上传必须挨个上传,也就是不能并行,得串行: 那么我们可以定义一个如下所示的上传函数: var serverIds = []; function uploadImages(localImage ...

随机推荐

  1. TJOI2013 DAY2

    第一题:明显先处理出最终序列,然后用线段树求解.处理最终序列可以用二分加树状数组(时间复杂度log2n, 用平衡树也可以搞...). /* * Problem: TJOI2013-day2-Seque ...

  2. Hibernate配置文件——hibernate.cfg.xml

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuratio ...

  3. JodaTime用法简介

    JodaTime用法简介 Java的Date和Calendar用起来简直就是灾难,跟C#的DateTime差距太明显了,幸好有JodaTime 本文简单罗列JodaTime的用法 package co ...

  4. [iOS 多线程 & 网络 - 2.0] - 发送接收 服务器信息

    A.搭建java服务器 使用eclipse.tomcat和struts2框架搭建一个简单的服务器 1.准备好合适版本的JDK.eclipse EE.tomcat.struts2 框架包 2.配置JDK ...

  5. Spring 使用注解方式进行事物管理

    大家在使用spring的注解式事务管理时,对事务的传播行为和隔离级别可能有点不知所措,下边就详细的介绍下以备方便查阅. 事物注解方式: @Transactional 当标于类前时, 标示类中所有方法都 ...

  6. mmap和普通文件读写的区别和比较 & mmap的注意点

    参考 http://www.cnblogs.com/huxiao-tee/p/4660352.html 对linux文件系统不了解的朋友,请参阅我之前写的博文<从内核文件系统看文件读写过程> ...

  7. 使用WPF来创建 Metro UI程序

    本文转载:http://www.cnblogs.com/TianFang/p/3184211.html 这个是我以前网上看到的一篇文章,原文地址是:Building a Metro UI with W ...

  8. 超级终端和SecureCRT进行Console口的连接

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  9. 常用小方法 or 语法

    --> 获取外部文件 def groovyUtils = new GroovyUtils( context ) def xmlFilePath = groovyUtils.getProjectP ...

  10. Spring 的两个配置容器的讲解

    容器 是Spring框架的核心,是组件存活的地方.Spring容器使用DI管理所有组成应用系统的组件,协作组件之间建立联.而且, 这些对象简洁易懂,降低耦合性,支持重用,容易被测试. Spring提供 ...