欢迎光临Software MyZone,有问题可留言或到站点论坛发帖,争取第一时间帮忙解决 || 站点论坛:火龙论坛 || 淘宝小店:应小心的易淘屋 【欢迎大家提建设性意见】

CCScrollVIew Bug修改版:FDScrollView

本文为firedragonpzy原创,转载务必在明显处注明:
转载自【Softeware MyZone】原文链接: 
http://www.firedragonpzy.com.cn/index.php/archives/3083

欢迎热爱编程的朋友们参与到cocos2d-x编程中,为了给大家提供良好的交流环境,网站以开启QQ群
Software MyZone:66202765(群号,欢迎加入,若满,请加1群)
Software MyZone 1群(2dx):286504621
【加群请写:Software MyZone或者是firedragonpzy】
群论坛:火龙论坛正试运营阶段,欢迎大家多提些建设性意见……

在使用CCScrollView的时候可谓是困难百出啊,这里简单的写了下FDScrollView,主要是解决缩放问题和缩放过程中你整个场景的位置的问题,其实缩放的话原来的也可以,但是你不能只是使用setZoomScale,你还得同时缩放m_pContainer,费劲,我呢,目前FDScrollView还没有详细整理,先大体一贴,供使用:关于SSCrollView遇到的困难说着bug及使用,大家可以参考CCScrollView的使用,一下是封装库:
下面是我的:FDScrollView.h


//

//  FDScrollView.h

//  CKCastle

//

//  Created by firedragonpzy on 13-1-24.

//

//

#ifndef __CKCastle__FDScrollView__

#define __CKCastle__FDScrollView__

#include "cocos2d.h"

#include "cocos-ext.h"

USING_NS_CC;

USING_NS_CC_EXT;

class FDScrollView : public CCScrollView{

public:

static FDScrollView* create(CCSize size, CCNode* container = NULL);

virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);

virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);

virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);

virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

void onEnter();

void updateInset();

void setContentSize(const CCSize & size);

void setZoomScale(float s);

void deaccelerateScrolling(float dt);

bool initWithViewSize(CCSize size, CCNode* container = NULL);

};

#endif /* defined(__CKCastle__FDScrollView__) */

下面是我的:FDScrollView.cpp

//

//  FDScrollView.cpp

//  CKCastle

//

//  Created by firedragonpzy on 13-1-24.

//

//

#include "FDScrollView.h"

#define SCROLL_DEACCEL_RATEFD  0.95f

#define SCROLL_DEACCEL_DISTFD  1.0f

#define BOUNCE_DURATIONFD      0.15f

#define INSET_RATIOFD 0.02

void FDScrollView::onEnter()

{

CCLayer::onEnter();

m_fMinZoomScale = 0.5;

m_fMaxZoomScale = 1.0;

}

FDScrollView* FDScrollView::create(CCSize size, CCNode* container/* = NULL*/)

{

FDScrollView* pRet = new FDScrollView();

if (pRet && pRet->initWithViewSize(size, container))

{

pRet->autorelease();

}

else

{

CC_SAFE_DELETE(pRet);

}

return pRet;

}

bool FDScrollView::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 = false;

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;

}

bool FDScrollView::ccTouchBegan(CCTouch* touch, CCEvent* event)

{

if (!this->isVisible())

{

return false;

}

CCRect frame;

CCPoint frameOriginal = this->getParent()->convertToWorldSpace(this->getPosition());

frame = CCRectMake(frameOriginal.x, frameOriginal.y, m_tViewSize.width, m_tViewSize.height);

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

}

void FDScrollView::ccTouchMoved(CCTouch* touch, CCEvent* event)

{

if (!this->isVisible())

{

return;

}

if (m_pTouches->containsObject(touch))

{

if (m_pTouches->count() == 1 && m_bDragging && this->getZoomScale() != 0.5)

{ // scrolling

CCPoint moveDistance, newPoint, maxInset, minInset;

CCRect  frame;

float newX, newY;

m_bTouchMoved  = true;

CCPoint frameOriginal = this->getParent()->convertToWorldSpace(this->getPosition());

frame = CCRectMake(frameOriginal.x, frameOriginal.y, m_tViewSize.width, m_tViewSize.height);

newPoint     = this->convertTouchToNodeSpace((CCTouch*)m_pTouches->objectAtIndex(0));

moveDistance = ccpSub(newPoint, m_tTouchPoint);

m_tTouchPoint  = newPoint;

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;

}

m_pContainer->setPosition(ccpAdd(m_pContainer->getPosition(), moveDistance));

maxInset = m_fMaxInset;

minInset = m_fMinInset;

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

m_tScrollDistance     = ccpSub(moveDistance, ccp(newX - m_pContainer->getPosition().x, newY - m_pContainer->getPosition().y));

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

float tempScale = this->getZoomScale()*len/m_fTouchLength;

if (tempScale > 1.0f) {

tempScale = 1.0f;

}

if (tempScale < 0.5f) { tempScale = 0.5f; } this->setZoomScale(tempScale);

}

}

}

void FDScrollView::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(FDScrollView::deaccelerateScrolling));

}

m_pTouches->removeObject(touch);

}

if (m_pTouches->count() == 0)

{

m_bDragging = false;

m_bTouchMoved = false;

}

}

void FDScrollView::ccTouchCancelled(CCTouch* touch, CCEvent* event)

{

if (!this->isVisible())

{

return;

}

m_pTouches->removeObject(touch);

if (m_pTouches->count() == 0)

{

m_bDragging = false;

m_bTouchMoved = false;

}

}

void FDScrollView::setContentSize(const CCSize & size)

{

if (this->getContainer() != NULL)

{

this->getContainer()->setContentSize(size);

this->updateInset();

}

}

void FDScrollView::updateInset()

{

if (this->getContainer() != NULL)

{

m_fMaxInset = this->maxContainerOffset();

m_fMaxInset = ccp(m_fMaxInset.x + m_tViewSize.width * INSET_RATIOFD,

m_fMaxInset.y + m_tViewSize.height * INSET_RATIOFD);

m_fMinInset = this->minContainerOffset();

m_fMinInset = ccp(m_fMinInset.x - m_tViewSize.width * INSET_RATIOFD,

m_fMinInset.y - m_tViewSize.height * INSET_RATIOFD);

}

}

void FDScrollView::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);

this->m_pContainer->setScale(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));

this->schedule(schedule_selector(FDScrollView::deaccelerateScrolling));

}

}

void FDScrollView::deaccelerateScrolling(float dt)

{

if (m_bDragging)

{

this->unschedule(schedule_selector(FDScrollView::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);

m_tScrollDistance     = ccpSub(m_tScrollDistance, ccp(newX - m_pContainer->getPosition().x, newY - m_pContainer->getPosition().y));

m_tScrollDistance     = ccpMult(m_tScrollDistance, SCROLL_DEACCEL_RATEFD);

this->setContentOffset(ccp(newX,newY));

if ((fabsf(m_tScrollDistance.x)
fabsf(m_tScrollDistance.y) unschedule(schedule_selector(FDScrollView::deaccelerateScrolling));

this->relocateContainer(true);

}

}

目前使用这个的话,如果你开启bounce的话在缩放后bounce是有问题的,不知道使用自带的缩放效果是怎么样的,时间原因,就先供此方法,其余有时间整理……

Demo下载链接:https://github.com/firedragonpzy/FD_Libs.git

  1. void HelloWorld::scrollViewDidScroll(CCScrollView* view)
    {

    }
    void HelloWorld::scrollViewDidZoom(CCScrollView* view)
    {

    }

    你的缩放在哪里啊 ,怎么又上面的实现啊

    • scrollViewDidScroll 这个是滑动时触发的动作,相应的下面那个是缩放时触发的动作,缩放的话你参考CCScrollView的move函数