版本号源代码来自2.x,转载请注明

另我实现了能够循环的版本号http://blog.csdn.net/u011225840/article/details/31354703

1.继承树结构


能够看出,CCScrollView本质是CCLayer的一种,具备层的一切属性和方法。关于CCLayer的源代码分析,兴许会有。

2.重要的成员

 1.  CCScrollViewDelegate* m_pDelegate;

cocos2d-x中,运用了非常多delegate这样的模式。

以下简单的说明下delegate这样的模式。

(至于delegate与proxy的差别,请先參考下headfirst中的proxy三种情况,然后能够google差别。这里不再赘述。)

XXXDelegate中封装了接口(c++中的实现就是虚函数与必须实现的纯虚函数),类A中存在某些方法,比方说View中的getDataNum,View会依据数据的多少来确定界面的显示方式。可是A与数据并没有直接的关联。于是乎。在View A中的getDataNum会调用A内部的DataDelegate的方法来获取数据的多少。至于这个数据详细是什么,仅仅须要实现一个DataDelegate的详细类就可以。这样。View与数据的耦合度就很低。View仅仅依赖抽象的DataDelegate。
在兴许的源代码分析中。能够看出delegate的妙处。


3.源代码解析

3.1 ccTouchBegan



对于ccTouchBegan中的重要部分,我加入了凝视。能够通过代码看出。CCscrollView支持单点和双点触摸。
bool CCScrollView::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
if (!this->isVisible() || !m_bCanTouch)
{
return false;
} CCRect frame = getViewRect(); //dispatcher does not know about clipping. reject touches outside visible bounds.
/*
1. ccScrollView仅仅同意至多两个触摸点。多于两个后将不会觉得发成了触摸。
2. 当CCScrollView处于移动状态时,在此状态下新发生触摸将不会被觉得发生。
3.注意frame不是当前的尺寸。而是当前ViewSize的frame,也就是触摸点必须在显示的Rect内才会认定为触摸(能够通过setViewSize来设置大小)
*/
if (m_pTouches->count() > 2 ||
m_bTouchMoved ||
!frame.containsPoint(m_pContainer->convertToWorldSpace(m_pContainer->convertTouchToNodeSpace(touch))))
{
m_pTouches->removeAllObjects();
return false;
} if (!m_pTouches->containsObject(touch))
{
m_pTouches->addObject(touch);
}
//CCLOG("CCScrollView::ccTouchBegan %d", m_pTouches->count());
/*
当触摸点为1的时候,设置单点触摸的属性。 尤其是m_bDragging属性表示触摸行为是拖动
*/
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;
}
/*
当触摸点个数为2时,设置双点触摸的属性
*/
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;
}

3.2 ccTouchMoved

同上。代码里面加了凝视
void CCScrollView::ccTouchMoved(CCTouch* touch, CCEvent* event)
{ if (!this->isVisible())
{
return;
} /*
假设此时不同意滚动,则退出。 这个能够通过set函数设置。默觉得false
*/
if(this->m_bScrollLock)
{
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();
//获得当前点的坐标,而且获得当前点与上一次触碰点的距离(moveDistance也是CCPoint,x与y是当前点与上一点的x距离,y距离)
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;
}
//第一次移动。则将moveDistance置0
if (!m_bTouchMoved)
{
moveDistance = CCPointZero;
} m_tTouchPoint = newPoint;
m_bTouchMoved = true;
//点必须在viewRect内部
if (frame.containsPoint(this->convertToWorldSpace(newPoint)))
{
//依据能够移动的direction来设置moveDistance
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;
//滚动的CCPoint矢量设置
m_tScrollDistance = moveDistance;
this->setContentOffset(ccp(newX, newY));
}
}
//双点触摸时。效果是缩放。len是双点触摸每次移动时的距离。
//而m_fTouchLength是双点開始时的距离,会依据move过程中距离与初始距离的比例进行缩放
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);
}
}
}

单点触摸时。调用了一个函数叫setContentOffset。以下继续分析contentOffset。


setContentOffset

void CCScrollView::setContentOffset(CCPoint offset, bool animated/* = false*/)
{
//默认情况,不做处理
if (animated)
{ //animate scrolling
this->setContentOffsetInDuration(offset, BOUNCE_DURATION);
}
//好玩的东西哦
else
{ //set the container position directly
//是否做越界处理。什么是越界。就是当你拖动整个容器时,假设已经到了容器的边界。还能不能再拖动,能够通过set函数进行设置
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)); }
//CCLOG("The offset x is %f , y is %f",offset.x,offset.y);
m_pContainer->setPosition(offset); //伟大的delegate来了。当你在滚动过程中想做除了基本界面滚动的额外操作时,请依据自己的不同情况。实现该delegate~完美的依赖抽象的设计。nice
if (m_pDelegate != NULL)
{
m_pDelegate->scrollViewDidScroll(this);
}
}
}

双点触摸时,调用了一个重要的函数setZoomScale。

setZoomScale

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;
}
//缩放后中心的位置相对于world坐标系会产生offset,这里将offset进行计算
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);
//delegate的重新出现
if (m_pDelegate != NULL)
{
m_pDelegate->scrollViewDidZoom(this);
}
//将产生的offset进行处理
this->setContentOffset(ccpAdd(m_pContainer->getPosition(),offset));
}
}

3.3 ccTouchEnded

能坚持看到这里,已经能够看见胜利的曙光了。曙光。。

void CCScrollView::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
if (!this->isVisible())
{
return;
}
//将touch从pTouches中移除
if (m_pTouches->containsObject(touch))
{
//当剩下一个touch时。须要在每一帧调用方法deaccelerateScrolling
if (m_pTouches->count() == 1 && m_bTouchMoved)
{
this->schedule(schedule_selector(CCScrollView::deaccelerateScrolling));
}
m_pTouches->removeObject(touch);
//CCLOG("CCScrollView::ccTouchEnded %d", m_pTouches->count());
//m_pDelegate->scrollViewDidStop(this);
}
//没有touch时,须要设置状态
if (m_pTouches->count() == 0)
{
m_bDragging = false;
m_bTouchMoved = false;
}
}

deaccelerateScrolling

在这个函数中,有一个地方没有理解。求大神指点

void CCScrollView::deaccelerateScrolling(float dt)
{
//假设刚好在帧開始前 又有一个触摸点发生了began。造成了滚动状态,则取消并返回
if (m_bDragging)
{
this->unschedule(schedule_selector(CCScrollView::deaccelerateScrolling));
return;
} //好玩的东西来咯 float newX, newY;
CCPoint maxInset, minInset;
CCLOG("The end distance is %f",m_tScrollDistance.x);
//这里我不清楚为啥要出来,我用输出发如今move中。已经将此offset设置过了,不知为何还要设置,求大神解答。
m_pContainer->setPosition(ccpAdd(m_pContainer->getPosition(), m_tScrollDistance)); //是否同意越界,获得的inset信息
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);
//伟大的delegate。。。
m_pDelegate->scrollViewDidStop(this); }
}

relocateContainer


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);
}
//还是调用setContentOffset,可是须要动画
if (newY != oldPoint.y || newX != oldPoint.x)
{
this->setContentOffset(ccp(newX, newY), animated);
}
}

setContentOffsetInDuration

void CCScrollView::setContentOffsetInDuration(CCPoint offset, float dt)
{
CCFiniteTimeAction *scroll, *expire;
//滚动的偏移动画
scroll = CCMoveTo::create(dt, offset);
//滚动完毕后的动画(负责停止performedAnimatedScroll。而且调用delegate)
expire = CCCallFuncN::create(this, callfuncN_selector(CCScrollView::stoppedAnimatedScroll));
m_pContainer->runAction(CCSequence::create(scroll, expire, NULL));
//负责不停调用delegate
this->schedule(schedule_selector(CCScrollView::performedAnimatedScroll));
}


4.小结

看到这里,CCScrollView里面属于自己独有部分的东西基本已经看完。

能够看出:

1.CCScrollView支持两种操作,滚动和缩放。
2.CCScrollView通过delegate将数据与界面解耦。
3.CCScrollView本质是一个CClayer,他展示的是自己内部的container。而且CCScrollView的触摸以及展示是依据ViewSize 还不是本身的SIze决定的。


cocos2d-x CCScrollView 源代码分析的更多相关文章

  1. cocos2d-x 源代码分析 总文件夹

    这篇博客用来整理与cocos2d-x相关的工作,仅仅要有新的分析.扩展或者改动,都会更改此文章. 祝大家愉快~ 1.源代码分析 1.CCScrollView源代码分析 http://blog.csdn ...

  2. Cocos2d-x 源代码分析 : Scheduler(定时器) 源代码分析

    源代码版本号 3.1r,转载请注明 我也最终不out了,開始看3.x的源代码了.此时此刻的心情仅仅能是wtf! !!!!!!! !.只是也最终告别CC时代了. cocos2d-x 源代码分析文件夹 h ...

  3. cocos2d-x 源代码分析 : Ref (CCObject) 源代码分析 cocos2d-x内存管理策略

    从源代码版本号3.x.转载请注明 cocos2d-x 总的文件夹的源代码分析: http://blog.csdn.net/u011225840/article/details/31743129 1.R ...

  4. android-plugmgr源代码分析

    android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束.关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好.在这篇文章中,我 ...

  5. Twitter Storm源代码分析之ZooKeeper中的目录结构

    徐明明博客:Twitter Storm源代码分析之ZooKeeper中的目录结构 我们知道Twitter Storm的所有的状态信息都是保存在Zookeeper里面,nimbus通过在zookeepe ...

  6. 转:SDL2源代码分析

    1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...

  7. 转:RTMPDump源代码分析

    0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...

  8. 转:ffdshow 源代码分析

    ffdshow神奇的功能:视频播放时显示运动矢量和QP FFDShow可以称得上是全能的解码.编码器.最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远 ...

  9. UiAutomator源代码分析之UiAutomatorBridge框架

    上一篇文章<UIAutomator源代码分析之启动和执行>我们描写叙述了uitautomator从命令行执行到载入測试用例执行測试的整个流程.过程中我们也描写叙述了UiAutomatorB ...

随机推荐

  1. uoj386 【UNR #3】鸽子固定器

    link (似乎很久没写题解了) 题意: n个物品,每个物品有a,b两个值,给定A,B,现在最多选其中m个,要求最大化选出的物品中[b权值和的B次方-a极差的A次方]. $n\leq 2\times ...

  2. Android背后的设计思想——功能共享机制

    Android的系统设计,与别的智能手机操作系统有很大区别,甚至在以往的任何操作系统里,很难找到像Android这样进行全面地系统级创新的操作系统.从创新层面上来说,Android编程上的思想和支持这 ...

  3. bzoj 1458: 士兵占领 -- 最大流

    1458: 士兵占领 Time Limit: 10 Sec  Memory Limit: 64 MB Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵 ...

  4. ASP.NET中在一般处理程序中使用session的简单介绍

    这篇文章介绍了ASP.NET中在一般处理程序中使用session,有需要的朋友可以参考一下 <%@ WebHandler Language="C#" Class=" ...

  5. Switching regulator forms constant-current source

    Many applications require current sources rather than voltage sources. When you need a high-current ...

  6. gitignore / Delphi.gitignore

    https://github.com/github/gitignore/blob/master/Delphi.gitignore *.dcu *.~*~ *.local *.identcache __ ...

  7. Appium+python自动化13-native和webview切换

    前言 现在大部分app都是混合式的native+webview,对应native上的元素通过uiautomatorviewer很容易定位到,webview上的元素就无法识别了. 一.识别webview ...

  8. 宿主机訪问virtualBox中Ubuntu

    斌斌 (给我写信) 原创博文(http://blog.csdn.net/binbinxyz).转载请注明出处! 使用NAT模式.就是让虚拟系统借助NAT(网络地址转换)功能.不须要你进行不论什么其它的 ...

  9. 海思hi3518 opencv测试

    2.4.9的opencv 安装好交叉编译后,用Cmake 配置opencv 修改CMakeCache.txtCMAKE_EXE_LINKER_FLAGS:STRING=-lpthread -lrt - ...

  10. [Android 新特性] 改进明显 Android 4.4系统新特性解析

    Android 4.3发布半年之后,Android 4.4随着新一代Nexus5一起出现在了用户的面前,命名为从之前的Jelly Bean(果冻豆)换成了KitKat(奇巧).这个新系统究竟都有怎样的 ...