使用时注意是调用 setContainer 函数添加滚动内容,不能用addChild
参考:http://blog.csdn.net/onerain88/article/details/7775569
http://music.573114.com/Blog/Html/D96C/550230.html
http://blog.csdn.net/toss156/article/details/7884207
- <SPAN style="FONT-SIZE: 16px">glScissor((GLint)screenPos.x, (GLint)screenPos.y, (GLsizei)(m_tViewSize.width*s), (GLsizei)(m_tViewSize.height*s));</SPAN>
glScissor((GLint)screenPos.x, (GLint)screenPos.y, (GLsizei)(m_tViewSize.width*s), (GLsizei)(m_tViewSize.height*s));
1.用途和效果
ScrollView一般用在游戏的关卡选择这种类似的场景(比如愤怒的小鸟和割绳子的关卡选择),当然,也可以用在道具店等等一些选择菜单的场景。
滑动,浏览不同关卡菜单;点击不同的菜单精灵,处理不同的事件。
2.实现
(1) 首先需要一个创建一个CCScrollView的对象和一个“Container”(可以是CCLayer或者CCNode的对象,用来存放CCScrollView中的内容),我这里放置了两个精灵菜单选项
- <SPAN style="FONT-SIZE: 16px">// CCScrollView
- scrollView = CCScrollView::create();
- CCLayer *layer = CCLayer::create();
- CCSprite *sprite1 = CCSprite::create("HelloWorld.png");
- CCSprite *sprite2 = CCSprite::create("HelloWorld.png");
- layer->setAnchorPoint(CCPointZero);
- layer->setPosition(CCPointZero);
- // Menu
- CCMenuItemSprite *menuItem1 = CCMenuItemSprite::create(sprite1, sprite1, this, menu_selector(HelloWorld::menu1Callback));
- menuItem1->setPosition(ccpAdd(CCPointZero, ccp(size.width / 2, size.height / 2)));
- menuItem1->setScale(0.4f);
- CCMenuItemSprite *menuItem2 = CCMenuItemSprite::create(sprite2, sprite2, this, menu_selector(HelloWorld::menu2Callback));
- menuItem2->setPosition(ccpAdd(ccp(480, 0), ccp(size.width / 2, size.height / 2)));
- menuItem2->setScale(0.4f);
- CCMenu *menu = CCMenu::create(menuItem1, menuItem2, NULL);
- menu->setPosition(CCPointZero);
- layer->addChild(menu);</SPAN>
// CCScrollView
scrollView = CCScrollView::create();
CCLayer *layer = CCLayer::create();
CCSprite *sprite1 = CCSprite::create("HelloWorld.png");
CCSprite *sprite2 = CCSprite::create("HelloWorld.png");
layer->setAnchorPoint(CCPointZero);
layer->setPosition(CCPointZero);
// Menu
CCMenuItemSprite *menuItem1 = CCMenuItemSprite::create(sprite1, sprite1, this, menu_selector(HelloWorld::menu1Callback));
menuItem1->setPosition(ccpAdd(CCPointZero, ccp(size.width / 2, size.height / 2)));
menuItem1->setScale(0.4f);
CCMenuItemSprite *menuItem2 = CCMenuItemSprite::create(sprite2, sprite2, this, menu_selector(HelloWorld::menu2Callback));
menuItem2->setPosition(ccpAdd(ccp(480, 0), ccp(size.width / 2, size.height / 2)));
menuItem2->setScale(0.4f);
CCMenu *menu = CCMenu::create(menuItem1, menuItem2, NULL);
menu->setPosition(CCPointZero);
layer->addChild(menu);
(2) 设置CCScrollView的显示区域
为了使ScrollView显示更灵活,CCScrollView提供了一个显示区域的设置方法,我这里设置显示区域480x320,总的大小为960x320(假设有两屏需要显示)
- <SPAN style="FONT-SIZE: 16px"> layer->setContentSize(CCSizeMake(960, 320));
- scrollView->setContentSize(CCSizeMake(480, 320));
- scrollView->setContainer(layer);</SPAN>
layer->setContentSize(CCSizeMake(960, 320));
scrollView->setContentSize(CCSizeMake(480, 320));
scrollView->setContainer(layer);
这里用layer作为(1)中的container
(3) 补充,其实到这里就基本实现了CCScrollView最基本的用法,如果需要监听滑动的事件,可以继承CCScrollViewDelegate委托,实现以下两个方法
- <SPAN style="FONT-SIZE: 16px">public:
- void scrollViewDidScroll(CCScrollView* view);
- void scrollViewDidZoom(CCScrollView* view);</SPAN>
public:
void scrollViewDidScroll(CCScrollView* view);
void scrollViewDidZoom(CCScrollView* view);
3.校对
这里会有一个问题,那就是当滑动结束时,经常是在两页之间,也就是图2的情况,这种体验不太好,我简单看了一下CCScrollView的源码,发现并没有相关的设置,想必是作者考虑到无法定义每页的大小尺寸,所以没有提供吧!所以,如果需要,我们要额外加一段校对的代码
所以在HelloWorld这层,继承了触摸事件的响应方法,并在ccTouchEnded()方法中校对
- <SPAN style="FONT-SIZE: 16px">void HelloWorld::adjustScrollView()
- {
- // 关闭CCScrollView中的自调整
- scrollView->unscheduleAllSelectors();
- int x = scrollView->getContentOffset().x;
- int offset = (int) x % 480;
- // 调整位置
- CCPoint adjustPos;
- // 调整动画时间
- float adjustAnimDelay;
- if (offset < -240) {
- // 计算下一页位置,时间
- adjustPos = ccpSub(scrollView->getContentOffset(), ccp(480 + offset, 0));
- adjustAnimDelay = (float) (480 + offset) / ADJUST_ANIM_VELOCITY;
- }
- else {
- // 计算当前页位置,时间
- adjustPos = ccpSub(scrollView->getContentOffset(), ccp(offset, 0));
- // 这里要取绝对值,否则在第一页往左翻动的时,保证adjustAnimDelay为正数
- adjustAnimDelay = (float) abs(offset) / ADJUST_ANIM_VELOCITY;
- }
- // 调整位置
- scrollView->setContentOffsetInDuration(adjustPos, adjustAnimDelay);
- }</SPAN>
void HelloWorld::adjustScrollView()
{
// 关闭CCScrollView中的自调整
scrollView->unscheduleAllSelectors();
int x = scrollView->getContentOffset().x;
int offset = (int) x % 480;
// 调整位置
CCPoint adjustPos;
// 调整动画时间
float adjustAnimDelay;
if (offset < -240) {
// 计算下一页位置,时间
adjustPos = ccpSub(scrollView->getContentOffset(), ccp(480 + offset, 0));
adjustAnimDelay = (float) (480 + offset) / ADJUST_ANIM_VELOCITY;
}
else {
// 计算当前页位置,时间
adjustPos = ccpSub(scrollView->getContentOffset(), ccp(offset, 0));
// 这里要取绝对值,否则在第一页往左翻动的时,保证adjustAnimDelay为正数
adjustAnimDelay = (float) abs(offset) / ADJUST_ANIM_VELOCITY;
}
// 调整位置
scrollView->setContentOffsetInDuration(adjustPos, adjustAnimDelay);
}
在这里我会根据当前相对于半屏的宽度(240像素)作为判断标准,来决定滑动结束时的所在页
这里需要注意的是必须要先关闭CCScrollView的schedule方法,因为CCScrollView在最左边和最右边做了校对,但是对中间的部分没有做校对!
4.注意事项
(1) 如果需要校对这一步,HelloWorld层是需要实现触摸方法的,而触摸的优先级一定要大于CCScrollView对象(也就是说要CCScrollView对象先响应触摸事件,然后在由HelloWorld层响应),而CCScrollView默认设置的优先级是0,所以HelloWorld需要设置为大于0的值
- <SPAN style="FONT-SIZE: 16px">void HelloWorld::onEnter()
- {
- CCLayer::onEnter();
- CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true);
- }</SPAN>
void HelloWorld::onEnter()
{
CCLayer::onEnter();
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true);
}
(2) 这个Demo中是有一个问题的,也就是当点着菜单项滑动的时候是无效的,因为菜单的触摸事件的优先级是最高的,所以,如果真的要做这种效果,需要考虑自己来判断触摸事件的!
bool HelloWorld::init() { // // 1. super init first if ( !CCLayer::init() ) { return false; } CCSize size = CCDirector::sharedDirector()->getWinSize(); // 创建一个layer作为容器 CCLayer * containlayer = CCLayer::create(); CCSprite * sp = CCSprite::create("HelloWorld.png"); sp->setPosition(ccp(size.width*0.5,size.height*0.5)); CCSprite * sp2 = CCSprite::create("Default.png"); sp2->setPosition(ccp(sp->getContentSize().width, size.height*0.5)); // 往容器中添加节点 containlayer->addChild(sp); containlayer->addChild(sp2); containlayer->setContentSize(CCSizeMake(size.width*3, size.height)); // 创建视图添加当前layer CCScrollView * sc = CCScrollView::create(CCSizeMake(size.width* 2, size.height)); addChild(sc); sc->isDragging();//用户是否正在CCScrollView中操作 sc->isTouchMoved();//用户是否正在CCScrollView移动操作 sc->isBounceable();//是否开启弹性效果 sc->setBounceable(true);//设置CCScrollView有弹性效果 sc->setViewSize(CCSizeMake(size.width*2, size.height)); // 设置CCScrollView尺寸 sc->setContainer(containlayer);//设置容器 sc->getViewSize();//获取视图尺寸 // 务必在AppDelegate.cpp 中开启ios多点触莫的支持 sc->setTouchEnabled(true);//开启监听多触点 sc->setDelegate(this);//注册监听 return true; } void HelloWorld:: scrollViewDidScroll(CCScrollView * view) { CCLOG("CCScrollView移动"); } // 当scrollview发生缩放的时相应 void HelloWorld:: scrollViewDidZoom(CCScrollView * view) { CCLOG("CCScrollView放缩"); }
Cocos2d-x 2.0.1里面 集成了一些以前需要自己添加的控件,极大的方便作为开发者的我们。
今天给大家带来一个用CCScrollView 实现的帮主页面。
最终结果是这样的:
首先CCScrollView 在 Cocosd-x 的扩展库里面,要是使用的话,需要添加命名空间
- using namespace cocos2d::extension;
using namespace cocos2d::extension;
或者是用cocos2d-x 已经定义的宏
- USING_NS_CC_EXT;
USING_NS_CC_EXT;
然后如果我们要是用 ScrollView的话,需要实现它的Delegate,这个的话,如果是做过IOS开发的同学应该很容易理解,就像UIScrollView。
- class HelpScene : public cocos2d::CCLayer ,public CCScrollViewDelegate
- {
- public:
- void scrollViewDidScroll(CCScrollView* view);
- void scrollViewDidZoom(CCScrollView* view);
- public:
- ///其他方法:
- }
class HelpScene : public cocos2d::CCLayer ,public CCScrollViewDelegate
{
public:
void scrollViewDidScroll(CCScrollView* view);
void scrollViewDidZoom(CCScrollView* view);
public:
///其他方法:
}
添加一个CCScrollView,可以通过统一的create函数实现,
- // CCScrollView
- scrollView = CCScrollView::create(); //创建一个scrollview
- CCLayer *layer = CCLayer::create(); //创建一个层,作为滚动的内容
- char helpstr[30] = {0};
- for (int i=1;i<=6;i++)
- {
- sprintf(helpstr,"Help/Help_%02d_chs.png",i);
- CCSprite *sprite = CCSprite::create(helpstr);
- sprite->setScaleX(2.0);
- sprite->setScaleY(1.0);
- sprite->setPosition(ccp(size.width*(i-0.5),size.height/2+25));
- layer->addChild(sprite);
- }
- layer->setAnchorPoint(CCPointZero);
- layer->setPosition(CCPointZero);
- scrollView->setPosition(CCPointZero);
- scrollView->setContentOffset(CCPointZero);
- layer->setContentSize(CCSizeMake(480*6, 320)); //设置滚动区域的大小
- scrollView->setContentSize(CCSizeMake(480, 320)); //设置显示区域的大小
- scrollView->setContainer(layer); //设置需要滚动的内容
- scrollView->setTouchEnabled(false); //因为要自己实现触摸消息,所以这里设为false
- scrollView->setDelegate(this);
- scrollView->setDirection(CCScrollViewDirectionHorizontal); //设置滚动的方向,有三种可以选择
- this->addChild(scrollView);
// CCScrollView
scrollView = CCScrollView::create(); //创建一个scrollview
CCLayer *layer = CCLayer::create(); //创建一个层,作为滚动的内容
char helpstr[30] = {0};
for (int i=1;i<=6;i++)
{
sprintf(helpstr,"Help/Help_%02d_chs.png",i);
CCSprite *sprite = CCSprite::create(helpstr);
sprite->setScaleX(2.0);
sprite->setScaleY(1.0);
sprite->setPosition(ccp(size.width*(i-0.5),size.height/2+25));
layer->addChild(sprite);
}
layer->setAnchorPoint(CCPointZero);
layer->setPosition(CCPointZero);
scrollView->setPosition(CCPointZero);
scrollView->setContentOffset(CCPointZero);
layer->setContentSize(CCSizeMake(480*6, 320)); //设置滚动区域的大小
scrollView->setContentSize(CCSizeMake(480, 320)); //设置显示区域的大小
scrollView->setContainer(layer); //设置需要滚动的内容
scrollView->setTouchEnabled(false); //因为要自己实现触摸消息,所以这里设为false
scrollView->setDelegate(this);
scrollView->setDirection(CCScrollViewDirectionHorizontal); //设置滚动的方向,有三种可以选择
this->addChild(scrollView);