游戏人生(二),有一种东西叫CCScrollView
来源:互联网 发布:如何从icloud恢复数据 编辑:程序博客网 时间:2024/05/16 18:46
搞过app或者game'的一定不会陌生:CCScrollView还有CCTableView。如果不知道什么是CCScrollView,那么去看看testcpp或者testlua中的例子吧。
先说说CCScrollView:.cpp和.h文件在\cocos2d-x-2.2.3\extensions\GUI\目录下,所以要使用CCScrollView首先要引入头文件#include "cocos-ext.h",以及空间名USING_NS_CC_EXT; 如果头文件报错,那么请检查工程的配置,这里就不多说了无非是引用,link的输入和c/c++里面的附加包含目录。(ps:如果是个简单的工程个人建议你重新建个新工程)。
#include "cocos-ext.h"USING_NS_CC_EXT;void HelloWorld::initScroll(){ CCSize size = CCDirector::sharedDirector()->getWinSize(); CCScrollView* scroll = CCScrollView::create(size); //scroll->setViewSize(size); scroll->setDirection(kCCScrollViewDirectionVertical); //设置滚动方向 CCSprite* p1 = CCSprite::create("HelloWorld.png"); p1->ignoreAnchorPointForPosition(true); CCSprite* p2 = CCSprite::create("HelloWorld.png"); p2->setPosition(ccp(0,size.height)); p2->ignoreAnchorPointForPosition(true); CCLayer* conLayer = CCLayer::create(); conLayer->addChild(p1); conLayer->addChild(p2); scroll->setContainer(conLayer); scroll->setContentSize(CCSizeMake(size.width,320*2)); this->addChild(scroll);}运行以上代码,我们就可以使用Scrollview了,总结起来就是
1、create scrollview
2、create Container层
3、将内容add到containner层
4、container层add到scrollview,scrollview加入指定layer或者scene
这里有几个点需要注意:
1、setContentSize不是scrollview大小,而是可滑动面的大小,viewSize是滑动面大小。
2、setContentSize不能放在setContainer前面,如果放在前面,那么这个滑动后回自动回到第一页。
3、container层中的内容position需要手动设定
4、如果不create container层,那么CCScrollView会给你创建个一个,但是直接在scrollview下add多个node只会保留一个,原因在后面分析。
好了,最容易的部分写完了,下面分析一下CCScrollView的源码和一些让人蛋疼的东西。
CCScrollView::CCScrollView(): m_fZoomScale(0.0f), m_fMinZoomScale(0.0f), m_fMaxZoomScale(0.0f), m_pDelegate(NULL) //view管理器, m_eDirection(kCCScrollViewDirectionBoth) //滚动类型, m_bDragging(false), m_pContainer(NULL) //container层, m_bTouchMoved(false), m_bBounceable(false) //弹性开关, m_bClippingToBounds(false) //弹性开关, m_fTouchLength(0.0f), m_pTouches(NULL), m_fMinScale(0.0f), m_fMaxScale(0.0f){}
CCScrollView* CCScrollView::create(CCSize size, CCNode* container/* = NULL*/){ CCScrollView* pRet = new CCScrollView(); if (pRet && pRet->initWithViewSize(size, container)) { pRet->autorelease(); } else { CC_SAFE_DELETE(pRet); } return pRet;}
bool CCScrollView::initWithViewSize(CCSize size, CCNode *container/* = NULL*/){ if (CCLayer::init())//scrollview继承CCLayer { m_pContainer = container; if (!this->m_pContainer) { m_pContainer = CCLayer::create();//create container层 this->m_pContainer->ignoreAnchorPointForPosition(false); this->m_pContainer->setAnchorPoint(ccp(0.0f, 0.0f)); } this->setViewSize(size);//设置视图尺寸,如果使用CCScrollView::create() 引擎会设置 size 为 CCSizeMake(200, 200) setTouchEnabled(true); //scrollview 自然是要有触摸的 m_pTouches = new CCArray();//触点 array m_pDelegate = NULL; m_bBounceable = true; //默认弹性开启 m_bClippingToBounds = true; //m_pContainer->setContentSize(CCSizeZero); m_eDirection = kCCScrollViewDirectionBoth; //默认both滚动模式 m_pContainer->setPosition(ccp(0.0f, 0.0f)); m_fTouchLength = 0.0f; this->addChild(m_pContainer); m_fMinScale = m_fMaxScale = 1.0f; //默认放缩1.0 m_mapScriptHandler.clear(); //清理回调列表 return true; } return false;}
我们补习一下滚动模式,CCScrollView中定义了一个枚举类型来表示滚动模式
typedef enum { kCCScrollViewDirectionNone = -1, //不滚动 kCCScrollViewDirectionHorizontal = 0, //横向滚动 kCCScrollViewDirectionVertical, //竖向滚动 kCCScrollViewDirectionBoth //双向滚动} CCScrollViewDirection;
初始化就先说到这,在看看属性设置上一些东西
void CCScrollView::setContainer(CCNode * pContainer){ // Make sure that 'm_pContainer' has a non-NULL value since there are // lots of logic that use 'm_pContainer'. if (NULL == pContainer) return; this->removeAllChildrenWithCleanup(true); //这个就是多次使用setContainer却只能显示一个sprite的原因 this->m_pContainer = pContainer //如果setContentSize在setContainer之前,实际上设置的size给引擎自带的container,而不是目标container this->m_pContainer->ignoreAnchorPointForPosition(false); this->m_pContainer->setAnchorPoint(ccp(0.0f, 0.0f)); this->addChild(this->m_pContainer); this->setViewSize(this->m_tViewSize);}
void CCScrollView::setViewSize(CCSize size){ m_tViewSize = size; CCLayer::setContentSize(size); //这里不是container的size,而是scrollview的size}
void CCScrollView::setContentSize(const CCSize & size){ if (this->getContainer() != NULL) { this->getContainer()->setContentSize(size); //这里才是设置container的size this->updateInset(); //设置弹性状态下虚拟边界值。 }}
/**虽然setcontainer只能用一次,但是addchild却可以满足我们的愿望。 * make sure all children go to the container */void CCScrollView::addChild(CCNode * child, int zOrder, int tag){ child->ignoreAnchorPointForPosition(false); child->setAnchorPoint(ccp(0.0f, 0.0f)); if (m_pContainer != child) { m_pContainer->addChild(child, zOrder, tag); } else { CCLayer::addChild(child, zOrder, tag); }}
属性设置完了,显示是没问题了,不过scrollview到底是如何滚动的?
首先:virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
代码太多,这里就不全贴出来了,有兴趣可以自己去看源码。让我们把主要代码摘出来
void CCScrollView::setContentOffset(CCPoint offset, bool animated/* = false*/) //此方法在ccTouchMoved中调用,功能是将container移动到指定位置{ if (animated) { //animate scrolling this->setContentOffsetInDuration(offset, BOUNCE_DURATION);//将container移动到指定位置,BOUNCE_DURATION=0.15f,移动时间 } else { //set the container position directly if (!m_bBounceable) //未开启边界弹性 { const CCPoint minOffset = this->minContainerOffset(); const CCPoint maxOffset = this->maxContainerOffset(); offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x)); offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y)); } m_pContainer->setPosition(offset); if (m_pDelegate != NULL) { m_pDelegate->scrollViewDidScroll(this); //回调虚函数,由子类override。lua中可以注册该函数的回调 } }}
void CCScrollView::setContentOffsetInDuration(CCPoint offset, float dt) //好了,动画来了。{ CCFiniteTimeAction *scroll, *expire; scroll = CCMoveTo::create(dt, offset); expire = CCCallFuncN::create(this, callfuncN_selector(CCScrollView::stoppedAnimatedScroll)); m_pContainer->runAction(CCSequence::create(scroll, expire, NULL)); this->schedule(schedule_selector(CCScrollView::performedAnimatedScroll)); }
void CCScrollView::deaccelerateScrolling(float dt) //该方法是在ccTouchEnded中的主要内容 ,当滑动停止的时候,container还会移动一段距离。 if (m_bDragging) //拖拽的话该方法不会多次循环调用 { this->unschedule(schedule_selector(CCScrollView::deaccelerateScrolling)); return; } float newX, newY; CCPoint maxInset, minInset; m_pContainer->setPosition(ccpAdd(m_pContainer->getPosition(), m_tScrollDistance)); if (m_bBounceable) //弹性设置边界,该值>设置containerSize值。 { maxInset = m_fMaxInset; minInset = m_fMinInset; } else { maxInset = this->maxContainerOffset(); minInset = this->minContainerOffset(); } //check to see if offset lies within the inset bounds newX = MIN(m_pContainer->getPosition().x, maxInset.x); newX = MAX(newX, minInset.x); newY = MIN(m_pContainer->getPosition().y, maxInset.y); newY = MAX(newY, minInset.y); newX = m_pContainer->getPosition().x; newY = m_pContainer->getPosition().y; m_tScrollDistance = ccpSub(m_tScrollDistance, ccp(newX - m_pContainer->getPosition().x, newY - m_pContainer->getPosition().y)); m_tScrollDistance = ccpMult(m_tScrollDistance, SCROLL_DEACCEL_RATE); this->setContentOffset(ccp(newX,newY)); //滑动灵敏度判断,边界判断,结束定时任务,在每次移动结束都会调用 if ((fabsf(m_tScrollDistance.x) <= SCROLL_DEACCEL_DIST && fabsf(m_tScrollDistance.y) <= SCROLL_DEACCEL_DIST) || newY > maxInset.y || newY < minInset.y || newX > maxInset.x || newX < minInset.x || newX == maxInset.x || newX == minInset.x || newY == maxInset.y || newY == minInset.y) { this->unschedule(schedule_selector(CCScrollView::deaccelerateScrolling)); this->relocateContainer(true); //重新设置locate,边界弹性 }}
void CCScrollView::relocateContainer(bool animated) //没什么好说的,判断边界,如超出的话就移动回来{ CCPoint oldPoint, min, max; float newX, newY; min = this->minContainerOffset(); max = this->maxContainerOffset(); oldPoint = m_pContainer->getPosition(); newX = oldPoint.x; newY = oldPoint.y; if (m_eDirection == kCCScrollViewDirectionBoth || m_eDirection == kCCScrollViewDirectionHorizontal) { newX = MAX(newX, min.x); newX = MIN(newX, max.x); } if (m_eDirection == kCCScrollViewDirectionBoth || m_eDirection == kCCScrollViewDirectionVertical) { newY = MIN(newY, max.y); newY = MAX(newY, min.y); } if (newY != oldPoint.y || newX != oldPoint.x) { this->setContentOffset(ccp(newX, newY), animated); }}好了,到这里基本上大体就算一站了,还有些细节以及放缩就不在细说。那么我们搞了这么久究竟是要干什么?很简单,我们希望滑动可以自动匹配图片的大小。怎么做那?
方法一:修改源码:
1、添加一个成员变量,记录初始滑动位置。
2、添加成员变量:图片匹配size
3、修改relocateContainer,max,min取最近符合要求的坐标,setContentOffset or setContentOffsetInDuration即可
原理就是:
- touch开始的时候记录初始位置,在touch结束的时候, 获取结束时刻的时间和位置. 通过滑动距离等判断是否已经翻页,然后设置最终目标坐标。
- 方法二:自定义控件,继承CCScrollView,在ccTouchEnded末尾调用自定义函数,实现以上功能。
- 如果是lua开发,我推荐第一中方法,快速,修改相对少些,不用新增pkg文件。如果是c++的话,还是继承的好。
- 试着修改下源码,不仅有利于学习,而且有快感!!!
- 游戏人生(二),有一种东西叫CCScrollView
- 有一种东西叫OE
- 有一种境界叫感觉(二)
- 世界上有一种东西叫"思念",古人云
- (感人)有一种爱叫放手
- 有一种境界叫感觉(三)
- 有个东西叫梦想
- 有一种感情叫无缘,有一种放弃叫成全
- 有一种感情叫无缘,有一种放弃叫成全
- 有一种感情叫无缘,有一种放弃叫成全
- 有一种感情叫无缘,有一种放手叫成全
- 有一种美丽叫放弃
- 有一种味道叫思恋
- 有一种道理叫“实践”
- 有一种美丽叫放弃
- 有一种美丽叫放弃
- 有一种爱,叫放手
- 有一种美丽叫放弃
- 第十五周 项目1--工资数据的输入
- n514uo.hengxinmuju.comziheidifutuoyiche
- xp0wm7.hengxinmuju.comyoujizhuoduncanyunwei
- 谈谈我做过的关键词聚类
- 如何更深入地学习 Linux?
- 游戏人生(二),有一种东西叫CCScrollView
- KMP算法
- ZOJ 2722 Head-to-head match
- 关于抽象类
- 秒 毫秒 微秒 纳秒 皮秒
- 虚拟机搭建hadoop的全分布式集群-in detail (2)
- 用GDB 调试Java程序
- OpenGL位图操作
- “模”法无边-设计模式6