Cocos 2.2.3 ScrollView浅谈

前端之家收集整理的这篇文章主要介绍了Cocos 2.2.3 ScrollView浅谈前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

先感性认识一下ScrollView:

1、上图中ScrollView就是我们要创建的滚动视图,你可以给它指定大小,也可以按默认的200*200,ScrollView设定的区域,就是你内容可以显示的区域,超出区域部分将被隐藏

2、m_pContainer为具体显示项的容器,具体显示项就是紫色矩形,只有m_pContainer在ScrollView中的部分才可以被显示出来,m_pContainer是可以被拖动的

3、m_pContainer默认为CCLayer,当然你也可以自己创建,该容器以及容器下的子物体都是以左下角为锚点的

4、该控件在使用过程中是可以用委托来监控ScrollView的滚动和缩放过程的,具体见.h文件


使用小例:

#include "cocos-ext.h"
USING_NS_CC_EXT;

CCScrollView *scrollView = CCScrollView::create();
scrollView->setPosition(ccp(240,0));	//此处的位置为ScrollView左下角的位置
scrollView->setContentSize(CCSize(200,600));	//设置容器的位置
scrollView->setDirection(kCCScrollViewDirectionVertical);	//默认为双向都可滑动,此处改为只有垂直方向滑动
scrollView->setBounceable(true);	//可选项,根据需求决定超过边界后是否要开启弹动
scrollView->setContentOffset(ccp(0,-400));	//设置m_pContainer的初始偏移,因为容器左下角和ScrollView左下角是重合的,所以减多少,代表下移多少,横向一样
this->addChild(scrollView);

for(int i = 0; i < 10; i++)
{
	CCSprite * p = CCSprite::create("CloseNormal.png");
	p->setPositionY(i * 50);	//容器项的位置需要手动设定
	scrollView->addChild(p);	//此处默认为给m_pContainer添加容器项
}	



学习思路:

1.先打开TestCpp——TableViewTest,看下效果,虽然是TableView,但最终效果差不多

2.阅读CCScrollView.h——这一段大体浏览就好了

3.重点阅读CCScrollView.cpp文件——因为这个组件肯定是要根据需求进行定制的,所以要重点阅读,一个函数一个函数的看,后面源码中有贴我理解后的注释,希望能帮助同样有困惑的你

ps:虽然是2.2.3的,但我看了3.3的相关内容,相差不大,可以对照来看,同时当你遇到一些莫名其妙的语句的时候,相信自己,因为里面确实有一些小问题。

函数为单位来学习。


/****************************************************************************
 Copyright (c) 2012 cocos2d-x.org
 Copyright (c) 2010 Sangwoo Im
 
 http://www.cocos2d-x.org
 
 Permission is hereby granted,free of charge,to any person obtaining a copy
 of this software and associated documentation files (the "Software"),to deal
 in the Software without restriction,including without limitation the rights
 to use,copy,modify,merge,publish,distribute,sublicense,and/or sell
 copies of the Software,and to permit persons to whom the Software is
 furnished to do so,subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS",WITHOUT WARRANTY OF ANY KIND,EXPRESS OR
 IMPLIED,INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER
 LIABILITY,WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE,ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

#include "CCScrollView.h"

NS_CC_EXT_BEGIN

#define SCROLL_DEACCEL_RATE  0.95f
#define SCROLL_DEACCEL_DIST  1.0f
#define BOUNCE_DURATION      0.15f
#define INSET_RATIO          0.2f
#define MOVE_INCH            7.0f/160.0f

static float convertDistanceFromPointToInch(float pointDis)
{
    float factor = ( CCEGLView::sharedOpenGLView()->getScaleX() + CCEGLView::sharedOpenGLView()->getScaleY() ) / 2;
    return pointDis * factor / CCDevice::getDPI();
}


CCScrollView::CCScrollView()
: m_fZoomScale(0.0f),m_fMinZoomScale(0.0f),m_fMaxZoomScale(0.0f),m_pDelegate(NULL),m_eDirection(kCCScrollViewDirectionBoth),m_bDragging(false),m_pContainer(NULL),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()
{
    CC_SAFE_RELEASE(m_pTouches);
    this->unregisterScriptHandler(kScrollViewScroll);
    this->unregisterScriptHandler(kScrollViewZoom);
}

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

CCScrollView* CCScrollView::create()
{
    CCScrollView* pRet = new CCScrollView();
    if (pRet && pRet->init())
    {
        pRet->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(pRet);
    }
    return pRet;
}


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;
        m_mapScriptHandler.clear();
        return true;
    }
    return false;
}

bool CCScrollView::init()
{
    return this->initWithViewSize(CCSizeMake(200,200),NULL);
}

void CCScrollView::registerWithTouchDispatcher()
{//注册单点触摸事件

    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,CCLayer::getTouchPriority(),false);
}

bool CCScrollView::isNodeVisible(CCNode* node)
{//判断content中的节点是否可以在View中显示

    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());
}

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 CCScrollView::resume(CCObject* sender)
{//滚动条恢复

    CCObject* pObj = NULL;
    CCArray* pChildren = m_pContainer->getChildren();

    CCARRAY_FOREACH(pChildren,pObj)
    {
        CCNode* pChild = (CCNode*)pObj;
        pChild->resumeSchedulerAndActions();
    }

    m_pContainer->resumeSchedulerAndActions();
}

void CCScrollView::setTouchEnabled(bool e)
{//多点触摸开关

    CCLayer::setTouchEnabled(e);
    if (!e)
    {
        m_bDragging = false;
        m_bTouchMoved = false;
        m_pTouches->removeAllObjects();
    }
}

void CCScrollView::setContentOffset(CCPoint offset,bool animated/* = false*/)
{//设置内容容器的偏移

    if (animated)
    { //偏移过程是否使用动画效果
        this->setContentOffsetInDuration(offset,BOUNCE_DURATION);
    } 
    else
    { //直接设置容器位置

        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);   
        }
    }
}

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));
}

CCPoint CCScrollView::getContentOffset()
{//获取内容容器的偏移

    return m_pContainer->getPosition();
}

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));
    }
}

float CCScrollView::getZoomScale()
{//获取容器的缩放比
    return m_pContainer->getScale();
}

void CCScrollView::setZoomScale(float s,bool animated)
{//设置容器的缩放比

    if (animated)
    {
        this->setZoomScaleInDuration(s,BOUNCE_DURATION);
    }
    else
    {
        this->setZoomScale(s);
    }
}

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);
    }
}

void CCScrollView::setViewSize(CCSize size)
{//设置滚动视图大小

    m_tViewSize = size;
    CCLayer::setContentSize(size);
}

CCNode * CCScrollView::getContainer()
{//返回内容容器

    return this->m_pContainer;
}

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);
    this->m_pContainer = pContainer;

    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::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);
    }
}

CCPoint CCScrollView::maxContainerOffset()
{//获取内容容器的最大偏移量,最大是针对值来说的,其实此刻是没有偏移的

    return ccp(0.0f,0.0f);
}

CCPoint CCScrollView::minContainerOffset()
{//获取内容容器的最小偏移量,最小是针对值来说的,其实此刻是偏移最大的

    return ccp(m_tViewSize.width - m_pContainer->getContentSize().width*m_pContainer->getScaleX(),m_tViewSize.height - m_pContainer->getContentSize().height*m_pContainer->getScaleY());
}

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);
    }
}

void CCScrollView::stoppedAnimatedScroll(CCNode * node)
{//滚动结束时回调函数调用

    this->unschedule(schedule_selector(CCScrollView::performedAnimatedScroll));
    // After the animation stopped,"scrollViewDidScroll" should be invoked,this could fix the bug of lack of tableview cells.
    if (m_pDelegate != NULL)
    {
        m_pDelegate->scrollViewDidScroll(this);
    }
}

void CCScrollView::performedAnimatedScroll(float dt)
{//滚动过程中回调函数调用

    if (m_bDragging)
    {
        this->unschedule(schedule_selector(CCScrollView::performedAnimatedScroll));
        return;
    }

    if (m_pDelegate != NULL)
    {
        m_pDelegate->scrollViewDidScroll(this);
    }
}


const CCSize& CCScrollView::getContentSize() const
{//获取内容容器尺寸

	return m_pContainer->getContentSize();
}

void CCScrollView::setContentSize(const CCSize & size)
{//设置内容容器尺寸

    if (this->getContainer() != NULL)
    {
        this->getContainer()->setContentSize(size);
		this->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);
	}
}

/**
 * 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 {
		//因为在初始化的时候,m_pContainer会被赋值,所以添加为子节点的时候m_pContainer == child,此处是用于添加容器的
        CCLayer::addChild(child,tag);
    }
}

void CCScrollView::addChild(CCNode * child,int zOrder)
{//添加内容容器或给内容容器添加子节点
    this->addChild(child,child->getTag());
}

void CCScrollView::addChild(CCNode * child)
{//添加内容容器或给内容容器添加子节点
    this->addChild(child,child->getZOrder(),child->getTag());
}

/**
 * clip this view so that outside of the visible bounds can be hidden.
 */
void CCScrollView::beforeDraw()
{//剪裁超过滚动视图外的内容容器部分,使之不显示

    if (m_bClippingToBounds)
    {
		m_bScissorRestored = false;
        CCRect frame = getViewRect();
        if (CCEGLView::sharedOpenGLView()->isScissorEnabled()) {
            m_bScissorRestored = true;
            m_tParentScissorRect = CCEGLView::sharedOpenGLView()->getScissorRect();
            //set the intersection of m_tParentScissorRect and frame as the new scissor rect
            if (frame.intersectsRect(m_tParentScissorRect)) {
                float x = MAX(frame.origin.x,m_tParentScissorRect.origin.x);
                float y = MAX(frame.origin.y,m_tParentScissorRect.origin.y);
                float xx = MIN(frame.origin.x+frame.size.width,m_tParentScissorRect.origin.x+m_tParentScissorRect.size.width);
                float yy = MIN(frame.origin.y+frame.size.height,m_tParentScissorRect.origin.y+m_tParentScissorRect.size.height);
                CCEGLView::sharedOpenGLView()->setScissorInPoints(x,y,xx-x,yy-y);
            }
        }
        else {
            glEnable(GL_SCISSOR_TEST);
            CCEGLView::sharedOpenGLView()->setScissorInPoints(frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
        }
    }
}

/**
 * retract what's done in beforeDraw so that there's no side effect to
 * other nodes.
 */
void CCScrollView::afterDraw()
{//此处为剪裁结束,不太明白为什么要一直关闭剪裁测试

    if (m_bClippingToBounds)
    {
        if (m_bScissorRestored) {//restore the parent's scissor rect
            CCEGLView::sharedOpenGLView()->setScissorInPoints(m_tParentScissorRect.origin.x,m_tParentScissorRect.origin.y,m_tParentScissorRect.size.width,m_tParentScissorRect.size.height);
        }
        else {
            glDisable(GL_SCISSOR_TEST);
        }
    }
}

void CCScrollView::visit()
{//渲染部分还不太明白,此处重载应该是为了添加beforeDraw和afterDraw的

	// quick return if not visible
	if (!isVisible())
    {
		return;
    }

	kmGLPushMatrix();
	
    if (m_pGrid && m_pGrid->isActive())
    {
        m_pGrid->beforeDraw();
        this->transformAncestors();
    }

	this->transform();
    this->beforeDraw();

	if(m_pChildren)
    {
		ccArray *arrayData = m_pChildren->data;
		unsigned int i=0;
		
		// draw children zOrder < 0
		for( ; i < arrayData->num; i++ )
        {
			CCNode *child =  (CCNode*)arrayData->arr[i];
			if ( child->getZOrder() < 0 )
            {
				child->visit();
			}
            else
            {
				break;
            }
		}
		
		// this draw
		this->draw();
		
		// draw children zOrder >= 0
		for( ; i < arrayData->num; i++ )
        {
			CCNode* child = (CCNode*)arrayData->arr[i];
			child->visit();
		}
        
	}
    else
    {
		this->draw();
    }

    this->afterDraw();
	if ( m_pGrid && m_pGrid->isActive())
    {
		m_pGrid->afterDraw(this);
    }

	kmGLPopMatrix();
}

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))))	//触摸点不在滚动视图范围内,对比3.3后,此处世界坐标和局部坐标转来转去是没有意义的,直接获取坐标即可
    {
        return false;
    }

    if (!m_pTouches->containsObject(touch))
    {//将触摸点添加至触摸数组
        m_pTouches->addObject(touch);
    }

    if (m_pTouches->count() == 1)
    { // 拖动
        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;
}

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);
        }
    }
}

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

void CCScrollView::ccTouchCancelled(CCTouch* touch,CCEvent* event)
{
    if (!this->isVisible())
    {
        return;
    }
    m_pTouches->removeObject(touch); 
    if (m_pTouches->count() == 0)
    {
        m_bDragging = false;    
        m_bTouchMoved = false;
    }
}

CCRect CCScrollView::getViewRect()
{//获取滚动视图的矩形

    CCPoint screenPos = this->convertToWorldSpace(CCPointZero);
    
    float scaleX = this->getScaleX();
    float scaleY = this->getScaleY();
    
    for (CCNode *p = m_pParent; p != NULL; p = p->getParent()) {
        scaleX *= p->getScaleX();
        scaleY *= p->getScaleY();
    }

    // Support negative scaling. Not doing so causes intersectsRect calls
    // (eg: to check if the touch was within the bounds) to return false.
    // Note,CCNode::getScale will assert if X and Y scales are different.
    if(scaleX<0.f) {
        screenPos.x += m_tViewSize.width*scaleX;
        scaleX = -scaleX;
    }
    if(scaleY<0.f) {
        screenPos.y += m_tViewSize.height*scaleY;
        scaleY = -scaleY;
    }

    return CCRectMake(screenPos.x,screenPos.y,m_tViewSize.width*scaleX,m_tViewSize.height*scaleY);
}

//后面三个与脚本相关,不熟,不解释
void CCScrollView::registerScriptHandler(int nFunID,int nScriptEventType)
{
    this->unregisterScriptHandler(nScriptEventType);
    m_mapScriptHandler[nScriptEventType] = nFunID;
}
void CCScrollView::unregisterScriptHandler(int nScriptEventType)
{
    std::map<int,int>::iterator iter = m_mapScriptHandler.find(nScriptEventType);
    
    if (m_mapScriptHandler.end() != iter)
    {
        m_mapScriptHandler.erase(iter);
    }
}
int  CCScrollView::getScriptHandler(int nScriptEventType)
{
    std::map<int,int>::iterator iter = m_mapScriptHandler.find(nScriptEventType);
    
    if (m_mapScriptHandler.end() != iter)
        return iter->second;
    
    return 0;
}
NS_CC_EXT_END
原文链接:https://www.f2er.com/cocos2dx/339934.html

猜你在找的Cocos2d-x相关文章