CCScrollView/CCScrollView(滚动条setContainer setContentSize setContentOffsetInDuration setDelegate)
#ifndef __CCSCROLLVIEW_H__#define __CCSCROLLVIEW_H__#include "cocos2d.h"#include "ExtensionMacros.h"NS_CC_EXT_BEGIN/** * @addtogroup GUI * @{ */typedef enum {
使用事例
class testScene:public CCLayer,public extension::CCScrollViewDelegate //可以自写触摸回调 { extension::CCScrollView *scrollView; public: virtual void scrollViewDidScroll(cocos2d::extension::CCScrollView* view); virtual void scrollViewDidZoom(cocos2d::extension::CCScrollView* view); public: virtual bool init(); CREATE_FUNC(testScene); static CCScene* scene(); //virtual void registerWithTouchDispatcher(); virtual bool ccTouchBegan(CCTouch *pTouch,CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch,CCEvent *pEvent); virtual void ccTouchCancelled(CCTouch *pTouch,CCEvent *pEvent); virtual void adjustScrollView(); virtual void onEnter(); };
bool testScene::init()
{
if ( !CCLayer::init() )
{
return false;
}
CCScrollView* scrollView = CCScrollView::create();
CCLayer *continerLayer = CCLayer::create();
continerLayer->setAnchorPoint(CCPointZero);
continerLayer->setPosition(CCPointZero);
scrollView->setAnchorPoint(CCPointZero);
scrollView->setPosition(CCPointZero);
scrollView->setViewSize(CCSizeMake(900, 600)); //显示的区域(在窗口裁剪一块显示滚动layer) "this->"CCLayer::setContentSize(size);
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
pSprite->setAnchorPoint(CCPointZero);
//pSprite->setContentSize(ccp(900,600));//并不能让图片放大到屏幕大小对于sprite这个函数无意义(仅在最开始根据图片大小设置一下contentsize并且不随scale变化) getcontentsize得到精灵图片大小
参考-> boundingBox getContentSize
continerLayer->addChild(pSprite, 0,2);
//scrollView->setContentSize(CCSizeMake(1000, 600));
scrollView->setContainer(continerLayer);
continerLayer->setContentSize(CCSizeMake(1000, 600)); //与下一句等效 滑动层的总大小 即可滑动范围
//continerLayer->setPosition(100,0);
scrollView->setContentOffsetInDuration(ccp(100,0),1);//设置偏移量(同上句) 并在1秒内移动到该偏移量位置 //这个偏移量其实就是continerLayer左下点相对于可视区域的左下点的坐标
///scrollView->setZoomScaleInDuration(2,-1);//小于1时相当于调用setZoomScale 因为初始化时 m_fMinScale = m_fMaxScale = 1.0f;所以此句无效 会崩。。
// scrollView->setBounceable(false); //是否反弹
this->addChild(scrollView);
scrollView->setDelegate(this);//触摸回调
this->addChild(scrollView);
return true;
}
#ifndef __CCSCROLLVIEW_H__
#define __CCSCROLLVIEW_H__
#include "cocos2d.h"
#include "ExtensionMacros.h"
NS_CC_EXT_BEGIN
/**
* @addtogroup GUI
* @{
*/
typedef enum {
kCCScrollViewDirectionNone = -1,//无法滑动
kCCScrollViewDirectionHorizontal = 0,//水平滑动
kCCScrollViewDirectionVertical, //垂直滑动
kCCScrollViewDirectionBoth //自由滑动
} CCScrollViewDirection;
class CCScrollView;
class CCScrollViewDelegate//监听滑动 组合方式(而非继承)由CCScrollView使用
{
public:
virtual ~CCScrollViewDelegate() {}
virtual void scrollViewDidScroll(CCScrollView* view) = 0;// 滑动时调用
virtual void scrollViewDidZoom(CCScrollView* view) = 0;//缩放时调用
};
/**
* ScrollView support for cocos2d for iphone.
* It provides scroll view functionalities to cocos2d projects natively.
*/
class CCScrollView : public CCLayer
{
public:
CCScrollView();
virtual ~CCScrollView();
virtual void registerWithTouchDispatcher();//在触摸调度器中注册 滚动层
/
void CCScrollView::registerWithTouchDispatcher()
{
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, CCLayer::getTouchPriority(), false);
}
/static CCScrollView* create(CCSize size, CCNode* container = NULL); //创建滚动层 1、可视大小 2、父节点
static CCScrollView* create();
bool init();
//
bool CCScrollView::init()
{
return this->initWithViewSize(CCSizeMake(200, 200), NULL);
}
/bool initWithViewSize(CCSize size, CCNode* container = NULL);
//
bool CCScrollView::initWithViewSize(CCSize size, CCNode *container/* = NULL*/)
{
if (CCLayer::init())
{
m_pContainer = container;
if (!this->m_pContainer)
{
m_pContainer = CCLayer::create();
this->m_pContainer->ignoreAnchorPointForPosition(false);
this->m_pContainer->setAnchorPoint(ccp(0.0f, 0.0f));
}
this->setViewSize(size);
setTouchEnabled(true);
m_pTouches = new CCArray();
m_pDelegate = NULL;
m_bBounceable = true;
m_bClippingToBounds = true;
//m_pContainer->setContentSize(CCSizeZero);
m_eDirection = kCCScrollViewDirectionBoth;
m_pContainer->setPosition(ccp(0.0f, 0.0f));
m_fTouchLength = 0.0f;
this->addChild(m_pContainer);
m_fMinScale = m_fMaxScale = 1.0f;
return true;
}
return false;
}
/
void setContentOffset(CCPoint offset, bool animated = false);//设置滚动内容偏移量
void CCScrollView::setContentOffset(CCPoint offset, bool animated/* = false*/)
{
if (animated)
{ //animate scrolling
this->setContentOffsetInDuration(offset, BOUNCE_DURATION);
}
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);
}
}
}
/CCPoint getContentOffset();
void setContentOffsetInDuration(CCPoint offset, float dt);//
///
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 setZoomScale(float s);//
void CCScrollView::setZoomScale(float s)
{
if (m_pContainer->getScale() != s)
{
CCPoint oldCenter, newCenter;
CCPoint center;
if (m_fTouchLength == 0.0f)
{
center = ccp(m_tViewSize.width*0.5f, m_tViewSize.height*0.5f);
center = this->convertToWorldSpace(center);
}
else
{
center = m_tTouchPoint;
}
oldCenter = m_pContainer->convertToNodeSpace(center);
m_pContainer->setScale(MAX(m_fMinScale, MIN(m_fMaxScale, s)));
newCenter = m_pContainer->convertToWorldSpace(oldCenter);
const CCPoint offset = ccpSub(center, newCenter);
if (m_pDelegate != NULL)
{
m_pDelegate->scrollViewDidZoom(this);
}
this->setContentOffset(ccpAdd(m_pContainer->getPosition(),offset));
}
}
//
/*** Sets a new scale and does that for a predefined(预定义) duration. */
void setZoomScale(float s, bool animated);//
float getZoomScale();//
/*** Sets a new scale for container in a given duration.*/
void setZoomScaleInDuration(float s, float dt);
//
void CCScrollView::setZoomScaleInDuration(float s, float dt)
{
if (dt > 0)
{
if (m_pContainer->getScale() != s)
{
CCActionTween *scaleAction;
scaleAction = CCActionTween::create(dt, "zoomScale", m_pContainer->getScale(), s);
this->runAction(scaleAction);
}
}
else
{
this->setZoomScale(s);
}
}
/*** Returns the current container's minimum offset. You may want this while you animate scrolling by yourself*/
CCPoint minContainerOffset();
/*** Returns the current container's maximum offset. You may want this while you animate scrolling by yourself*/
CCPoint maxContainerOffset();
/**
* Determines(确定) if(是否) a given node's bounding(边框) box is in visible bounds
*/
bool isNodeVisible(CCNode * node); //
///
bool CCScrollView::isNodeVisible(CCNode* node)
{
const CCPoint offset = this->getContentOffset(); //这个偏移量其实就是起始点
const CCSize size = this->getViewSize();
const float scale = this->getZoomScale();
CCRect viewRect;
viewRect = CCRectMake(-offset.x/scale, -offset.y/scale, size.width/scale, size.height/scale);
return viewRect.intersectsRect(node->boundingBox()); //是否相交
}
/**
* Provided(提供) to make scroll view compatible(兼容) with SWLayer's pause method
*/
void pause(CCObject* sender);
///
void CCScrollView::pause(CCObject* sender)
{
m_pContainer->pauseSchedulerAndActions();
CCObject* pObj = NULL;
CCArray* pChildren = m_pContainer->getChildren();
CCARRAY_FOREACH(pChildren, pObj)
{
CCNode* pChild = (CCNode*)pObj;
pChild->pauseSchedulerAndActions();
}
}
/
void resume(CCObject* sender);
bool isDragging() {return m_bDragging;} //Dragging 拖曳用的
bool isTouchMoved() { return m_bTouchMoved; }
bool isBounceable() { return m_bBounceable; }//反弹
void setBounceable(bool bBounceable) { m_bBounceable = bBounceable; }
//可视大小
CCSize getViewSize() { return m_tViewSize; } //
void setViewSize(CCSize size);
CCNode * getContainer();//
void setContainer(CCNode * pContainer);
CCScrollViewDirection getDirection() { return m_eDirection; } //可滑动方向设置
virtual void setDirection(CCScrollViewDirection eDirection) { m_eDirection = eDirection; }
CCScrollViewDelegate* getDelegate() { return m_pDelegate; }
void setDelegate(CCScrollViewDelegate* pDelegate) { m_pDelegate = pDelegate; } //设置滑动协议来监听滑动
/** override functions */ //重写触摸回调
// optional
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
//
bool CCScrollView::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
if (!this->isVisible())
{
return false;
}
CCRect frame = getViewRect();
//dispatcher does not know about clipping. reject touches outside visible bounds.
if (m_pTouches->count() > 2 ||
m_bTouchMoved ||
!frame.containsPoint(m_pContainer->convertToWorldSpace(m_pContainer->convertTouchToNodeSpace(touch))))
{
return false;
}
if (!m_pTouches->containsObject(touch))
{
m_pTouches->addObject(touch);
}
if (m_pTouches->count() == 1)
{ // scrolling
m_tTouchPoint = this->convertTouchToNodeSpace(touch);
m_bTouchMoved = false;
m_bDragging = true; //dragging started
m_tScrollDistance = ccp(0.0f, 0.0f);
m_fTouchLength = 0.0f;
}
else if (m_pTouches->count() == 2)
{
m_tTouchPoint = ccpMidpoint(this->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(0)),
this->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(1)));
m_fTouchLength = ccpDistance(m_pContainer->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(0)),
m_pContainer->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(1)));
m_bDragging = false;
}
return true;
}
/
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
void CCScrollView::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
if (!this->isVisible())
{
return;
}
if (m_pTouches->containsObject(touch))
{
if (m_pTouches->count() == 1 && m_bDragging)
{ // scrolling
CCPoint moveDistance, newPoint, maxInset, minInset;
CCRect frame;
float newX, newY;
frame = getViewRect();
newPoint = this->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(0));
moveDistance = ccpSub(newPoint, m_tTouchPoint);
float dis = 0.0f;
if (m_eDirection == kCCScrollViewDirectionVertical)
{
dis = moveDistance.y;
}
else if (m_eDirection == kCCScrollViewDirectionHorizontal)
{
dis = moveDistance.x;
}
else
{
dis = sqrtf(moveDistance.x*moveDistance.x + moveDistance.y*moveDistance.y);
}
if (!m_bTouchMoved && fabs(convertDistanceFromPointToInch(dis)) < MOVE_INCH )
{
//CCLOG("Invalid movement, distance = [%f, %f], disInch = %f", moveDistance.x, moveDistance.y);
return;
}
if (!m_bTouchMoved)
{
moveDistance = CCPointZero;
}
m_tTouchPoint = newPoint;
m_bTouchMoved = true;
if (frame.containsPoint(this->convertToWorldSpace(newPoint)))
{
switch (m_eDirection)
{
case kCCScrollViewDirectionVertical:
moveDistance = ccp(0.0f, moveDistance.y);
break;
case kCCScrollViewDirectionHorizontal:
moveDistance = ccp(moveDistance.x, 0.0f);
break;
default:
break;
}
maxInset = m_fMaxInset;
minInset = m_fMinInset;
newX = m_pContainer->getPosition().x + moveDistance.x;
newY = m_pContainer->getPosition().y + moveDistance.y;
m_tScrollDistance = moveDistance;
this->setContentOffset(ccp(newX, newY));
}
}
else if (m_pTouches->count() == 2 && !m_bDragging)
{
const float len = ccpDistance(m_pContainer->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(0)),
m_pContainer->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(1)));
this->setZoomScale(this->getZoomScale()*len/m_fTouchLength);
}
}
}
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
/
void CCScrollView::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
if (!this->isVisible())
{
return;
}
if (m_pTouches->containsObject(touch))
{
if (m_pTouches->count() == 1 && m_bTouchMoved)
{
this->schedule(schedule_selector(CCScrollView::deaccelerateScrolling));
}
m_pTouches->removeObject(touch);
}
if (m_pTouches->count() == 0)
{
m_bDragging = false;
m_bTouchMoved = false;
}
}
/virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
virtual void setContentSize(const CCSize & size); //设置ContentSize
virtual const CCSize& getContentSize() const;
void updateInset();
void CCScrollView::updateInset()
{
if (this->getContainer() != NULL)
{
m_fMaxInset = this->maxContainerOffset();
m_fMaxInset = ccp(m_fMaxInset.x + m_tViewSize.width * INSET_RATIO,
m_fMaxInset.y + m_tViewSize.height * INSET_RATIO);
m_fMinInset = this->minContainerOffset();
m_fMinInset = ccp(m_fMinInset.x - m_tViewSize.width * INSET_RATIO,
m_fMinInset.y - m_tViewSize.height * INSET_RATIO);
}
}
/
/**
* Determines whether it clips(修剪) its children or not.
*/
bool isClippingToBounds() { return m_bClippingToBounds; }
void setClippingToBounds(bool bClippingToBounds) { m_bClippingToBounds = bClippingToBounds; }
virtual void visit();
virtual void addChild(CCNode * child, int zOrder, int tag);
virtual void addChild(CCNode * child, int zOrder);
virtual void addChild(CCNode * child);
void setTouchEnabled(bool e);
private: //以下是私有的 内部调用 外部用不到所以知道即可
void relocateContainer(bool animated);//根据max/min 偏移量重设位置
/**
* implements(实施 执行) auto-scrolling behavior. change SCROLL_DEACCEL_RATE as needed to choose
* deceleration(减(速)) speed. it must be less than 1.0f.
*/
void deaccelerateScrolling(float dt); //设置减速滚动
//
void CCScrollView::deaccelerateScrolling(float dt)
{
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)
{
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);
}
}
/**
* This method makes sure auto scrolling causes delegate to invoke(调用) its method
*/
void performedAnimatedScroll(float dt);
/**
* Expire(终止) animated(活的) scroll delegate calls
*/
void stoppedAnimatedScroll(CCNode* node);
/**
* clip this view so that outside of the visible bounds can be hidden.
*/
void beforeDraw();
/**
* retract what's done in beforeDraw so that there's no side effect to
* other nodes.
*/
void afterDraw();
/**
* Zoom handling
*/
void handleZoom();
protected:
CCRect getViewRect(); //得到view区域
float m_fZoomScale;//当前scale
float m_fMinZoomScale;//min scale
float m_fMaxZoomScale;//max scale
CCScrollViewDelegate* m_pDelegate;//滚动条协议
CCScrollViewDirection m_eDirection;
bool m_bDragging;
CCPoint m_tContentOffset;
CCNode* m_pContainer;
bool m_bTouchMoved;
/**
* max inset(插入) point to limit scrolling by touch
*/
CCPoint m_fMaxInset; //滚动触摸最大范围
/**
* min inset point to limit scrolling by touch
*/
CCPoint m_fMinInset;//滚动触摸最小范围
bool m_bBounceable;//是否反弹
bool m_bClippingToBounds;//
/**
* scroll speed
*/
CCPoint m_tScrollDistance; //滚动速度
CCPoint m_tTouchPoint; //触摸点
float m_fTouchLength; //两指间距
/**
* UITouch objects to detect multitouch
*/
CCArray* m_pTouches;
CCSize m_tViewSize;///
/**
*max and min scale
*/
float m_fMinScale, m_fMaxScale;
/**
* scissor rect for parent, just for restoring GL_SCISSOR_BOX
*/
CCRect m_tParentScissorRect;//
bool m_bScissorRestored;/
};
NS_CC_EXT_END
#endif
更多推荐
所有评论(0)