cocos2d-x CCScrollView 源代码分析
版本号源代码来自2.x,转载请注明
另我实现了能够循环的版本号http://blog.csdn.net/u011225840/article/details/31354703
1.继承树结构
2.重要的成员
以下简单的说明下delegate这样的模式。
(至于delegate与proxy的差别,请先參考下headfirst中的proxy三种情况,然后能够google差别。这里不再赘述。)
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
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.小结
能够看出:
cocos2d-x CCScrollView 源代码分析的更多相关文章
- cocos2d-x 源代码分析 总文件夹
这篇博客用来整理与cocos2d-x相关的工作,仅仅要有新的分析.扩展或者改动,都会更改此文章. 祝大家愉快~ 1.源代码分析 1.CCScrollView源代码分析 http://blog.csdn ...
- Cocos2d-x 源代码分析 : Scheduler(定时器) 源代码分析
源代码版本号 3.1r,转载请注明 我也最终不out了,開始看3.x的源代码了.此时此刻的心情仅仅能是wtf! !!!!!!! !.只是也最终告别CC时代了. cocos2d-x 源代码分析文件夹 h ...
- cocos2d-x 源代码分析 : Ref (CCObject) 源代码分析 cocos2d-x内存管理策略
从源代码版本号3.x.转载请注明 cocos2d-x 总的文件夹的源代码分析: http://blog.csdn.net/u011225840/article/details/31743129 1.R ...
- android-plugmgr源代码分析
android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束.关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好.在这篇文章中,我 ...
- Twitter Storm源代码分析之ZooKeeper中的目录结构
徐明明博客:Twitter Storm源代码分析之ZooKeeper中的目录结构 我们知道Twitter Storm的所有的状态信息都是保存在Zookeeper里面,nimbus通过在zookeepe ...
- 转:SDL2源代码分析
1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...
- 转:RTMPDump源代码分析
0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...
- 转:ffdshow 源代码分析
ffdshow神奇的功能:视频播放时显示运动矢量和QP FFDShow可以称得上是全能的解码.编码器.最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远 ...
- UiAutomator源代码分析之UiAutomatorBridge框架
上一篇文章<UIAutomator源代码分析之启动和执行>我们描写叙述了uitautomator从命令行执行到载入測试用例执行測试的整个流程.过程中我们也描写叙述了UiAutomatorB ...
随机推荐
- [CodeForces850C]Arpa and a game with Mojtaba
题目大意: 给你一个包含n个数的数列,两个人轮流对数列进行如下操作: 选择一个质数p和一个正整数k,将数列中所有能被p^k整除的数除以p^k. 最后不能操作者负. 问先手是否有必胜策略. 思路: 显然 ...
- Request Response 跳转页面的理解
1.response 跳转页面 private void writeContent(String content) { HttpServletResponse response = ((Servlet ...
- bzoj 2038 小z的袜子 莫队例题
莫队,利用可以快速地通过一个问题的答案得到另一问题的答案这一特性,合理地组织问题的求解顺序,将已解决的问题帮助解决当前问题,来优化时间复杂度. 典型用法:处理静态(无修改)离线区间查询问题. 线段树也 ...
- 区间DP--凸多边形三角剖分
给定一个具有N(N<50)个顶点(从1到N编号)的凸多边形,每个顶点的权均已知.问如何把这个凸多边形划分成N-2个互不相交的三角形,使得这些三角形顶点的权的乘积之和最小? 输入文件:第一行 顶点 ...
- nodejs中间件拦截,express不登录无法进入后台页面
22.设置拦截 只有登录才能进入到后台页面,不登录无法进入 如果登陆成功, 写入session, 参数 uid uid=123dsfjksldfjsl 检测登陆, 请求中 session 是否包含 u ...
- 关于JAVA_HOME, CLASSPATH和PATH的设置
http://bbs.csdn.net/topics/120079565 1.PATH,这个是给WINDOWS操作系统用的,告诉命令行里,执行的命令行工具在那里,比如java,javac这都是命令行工 ...
- Android Studio开发Android问题集【持续更新】
问题一:emulator:ERROR:This AVD's configuration is missing a kernel file!! 答:打开Android SDK Manager,查看相应的 ...
- picker.js源码
/** * LArea移动端城市选择控件 * * version:1.7.2 * * author:黄磊 * * git:https://github.com/xfhxbb/LArea * * Cop ...
- Andorid之Annotation框架初使用(五)
注入res文件夹的资源: @StringRes @EActivity public class MyActivity extends Activity { @StringRes(R.string.he ...
- github pages+hexo自建博客
1.github创建新项目,然后开启pages即可 2.全局安装hexo npm install -g hexo 3.初始化hexo hexo init 4.安装hexo的依赖 npm i 5.基本上 ...