原来在公司被迫加班加点赶工,用lua实现的版本:http://www.cnblogs.com/mmc1206x/p/4146911.html

后来因我个人的需要, 用C++实现了一个版本.

蓦然回首, lua那版不忍直视, 设计拙劣, 代码拙劣, 当然, 这都归咎于那时的我太年轻.

效果图

ScrollView.h

  1. #pragma once
  2.  
  3. #include "Base.h"
  4.  
  5. class ScrollView : public ccNode {
  6. public:
  7. struct Param {
  8. float scale;
  9. float width;
  10. float height;
  11. float itemWidth;
  12. float itemHeight;
  13. float anchorY;
  14. std::function<void(ccNode *)> enterHandler;
  15. std::function<void(ccNode *)> leaveHandler;
  16. Param()
  17. : scale()
  18. , width()
  19. , height()
  20. , itemWidth()
  21. , itemHeight()
  22. , anchorY(0.5f)
  23. , enterHandler([](ccNode *){})
  24. , leaveHandler([](ccNode *){})
  25. {
  26.  
  27. }
  28. };
  29. public:
  30. virtual void addChild(ccNode *pNode) override;
  31. virtual void removeChild(ccNode *pNode, bool cleanup = true) override;
  32.  
  33. void gotoIndex(int index)
  34. {
  35. _touchIdx = index;
  36. runUpdate();
  37. }
  38.  
  39. ccNode *getActiveNode()
  40. {
  41. return getNode(_activeIdx);
  42. }
  43.  
  44. ccNode *getTouchNode()
  45. {
  46. return getNode(_touchIdx);
  47. }
  48.  
  49. ccNode *getNode(u_int index)
  50. {
  51. auto &childs = getChildren();
  52. return index < (u_int)childs.size()
  53. ? childs.at(index) : nullptr;
  54. }
  55.  
  56. float getNodeOffset(u_int index)
  57. {
  58. auto offset = getNodePos(index);
  59. auto max = getRight();
  60. auto min = getLeft();
  61. if (offset <= max && offset >= min)
  62. {
  63. offset -= (max - offset) * (_param.scale - );
  64. }
  65. else if (offset < min)
  66. {
  67. offset -= (max - min) * (_param.scale - );
  68. }
  69. return offset;
  70. }
  71. private:
  72. bool onTouchBegan(ccTouch *pTouch, ccEvent *pEvent);
  73. void onTouchMoved(ccTouch *pTouch, ccEvent *pEvent);
  74. void onTouchEnded(ccTouch *pTouch, ccEvent *pEvent);
  75. void onTouchCancelled(ccTouch *pTouch, ccEvent *pEvent);
  76. bool moveChilds(float diff);
  77. u_int getNodeIdx(const ccVec2 &worldPoint);
  78. virtual void update(float dt) override;
  79.  
  80. void setActive(u_int index)
  81. {
  82. auto pOldNode = getActiveNode();
  83. auto pNewNode = getNode(index);
  84. MMC_ASSERT(pNewNode != nullptr);
  85. if (pOldNode != pNewNode)
  86. {
  87. _activeIdx = index;
  88. if (pOldNode != nullptr)
  89. {
  90. _param.leaveHandler(pOldNode);
  91. }
  92. _param.enterHandler(pNewNode);
  93. }
  94. }
  95.  
  96. private:
  97. float getNodePos(u_int index)
  98. {
  99. return _param.itemWidth * index + _offset;
  100. }
  101.  
  102. float getRight()
  103. {
  104. ;
  105. }
  106.  
  107. float getLeft()
  108. {
  109. return getRight() - _param.itemWidth;
  110. }
  111.  
  112. bool isActive(u_int index)
  113. {
  114. auto offset = getNodePos(index);
  115. return offset <= getRight() && offset >= getLeft();
  116. }
  117.  
  118. void stopUpdate()
  119. {
  120. unscheduleUpdate();
  121. }
  122.  
  123. void runUpdate()
  124. {
  125. scheduleUpdate();
  126. }
  127.  
  128. private:
  129. ScrollView();
  130. ~ScrollView();
  131. void mmcInit(const Param &param);
  132.  
  133. friend ScrollView *utils::createCocos<ScrollView>(const Param &);
  134.  
  135. private:
  136. ccEventListenerTouchOneByOne *_listener;
  137. Param _param;
  138. float _offset;
  139. int _activeIdx;
  140. int _touchIdx;
  141. int _tick;
  142. };

ScrollView.cpp

  1. #include "ScrollView.h"
  2.  
  3. ScrollView::ScrollView()
  4. : _listener(nullptr)
  5. , _activeIdx(INVALID_VALUE)
  6. , _touchIdx(INVALID_VALUE)
  7. , _offset()
  8. {
  9. }
  10.  
  11. ScrollView::~ScrollView()
  12. {
  13. }
  14.  
  15. void ScrollView::mmcInit(const Param &param)
  16. {
  17. if (!Node::init())
  18. {
  19. MMC_ASSERT(false);
  20. }
  21. _listener = ccEventListenerTouchOneByOne::create();
  22. _listener->onTouchBegan = CC_CALLBACK_2(ScrollView::onTouchBegan, this);
  23. _listener->onTouchMoved = CC_CALLBACK_2(ScrollView::onTouchMoved, this);
  24. _listener->onTouchEnded = CC_CALLBACK_2(ScrollView::onTouchEnded, this);
  25. _listener->onTouchCancelled = CC_CALLBACK_2(ScrollView::onTouchCancelled, this);
  26. _listener->setSwallowTouches(true);
  27. getEventDispatcher()->addEventListenerWithSceneGraphPriority(_listener, this);
  28. _offset = ;
  29. _param = param;
  30. runUpdate();
  31. }
  32.  
  33. void ScrollView::addChild(ccNode *pNode)
  34. {
  35. auto childCount = getChildrenCount();
  36. auto offset = getNodeOffset(childCount);
  37. pNode->setPositionX(offset);
  38. pNode->setAnchorPoint(ccVec2(0.5f, _param.anchorY));
  39. if (_activeIdx == INVALID_VALUE && _touchIdx == INVALID_VALUE)
  40. {
  41. _touchIdx = childCount;
  42. runUpdate();
  43. }
  44. Node::addChild(pNode);
  45. }
  46.  
  47. void ScrollView::removeChild(Node *pNode, bool cleanup)
  48. {
  49. auto pActive = getActiveNode();
  50. if (pActive == pNode)
  51. {
  52. _activeIdx = INVALID_VALUE;
  53. }
  54. auto pTouch = getTouchNode();
  55. if (pTouch == pNode)
  56. {
  57. _touchIdx = INVALID_VALUE;
  58. }
  59. Node::removeChild(pNode, cleanup);
  60. }
  61.  
  62. bool ScrollView::onTouchBegan(ccTouch *pTouch, ccEvent *pEvent)
  63. {
  64. const auto &size = getContentSize();
  65. const auto &touchRect = ccRect(
  66. _param.width * -0.5f,
  67. _param.height * -_param.anchorY,
  68. _param.width, _param.height);
  69. const auto &worldPoint = pTouch->getLocation();
  70. const auto &localPoint = convertToNodeSpace(worldPoint);
  71. auto isTouch = touchRect.containsPoint(localPoint);
  72. if (isTouch)
  73. {
  74. _tick = clock();
  75. stopUpdate();
  76. }
  77. return isTouch;
  78. }
  79.  
  80. void ScrollView::onTouchMoved(ccTouch *pTouch, ccEvent *pEvent)
  81. {
  82. auto diffOffset = pTouch->getDelta().x;
  83. auto nowtick = clock();
  84. auto difftick = nowtick - _tick;
  85. #ifdef WIN32
  86. ;
  87. #else
  88. / ;
  89. #endif
  90. _tick = nowtick;
  91. _touchIdx = _activeIdx - offsetIndex;
  92. if (_touchIdx >= getChildrenCount())
  93. {
  94. _touchIdx = getChildrenCount() - ;
  95. }
  96. )
  97. {
  98. _touchIdx = ;
  99. }
  100. moveChilds(diffOffset);
  101. }
  102.  
  103. void ScrollView::onTouchEnded(ccTouch *pTouch, ccEvent *pEvent)
  104. {
  105. const auto &beg = pTouch->getStartLocation();
  106. const auto &end = pTouch->getLocation();
  107. const auto &delta = beg.getDistance(end);
  108. )
  109. {
  110. _touchIdx = getNodeIdx(end);
  111. }
  112. runUpdate();
  113. }
  114.  
  115. void ScrollView::onTouchCancelled(ccTouch *pTouch, ccEvent *pEvent)
  116. {
  117.  
  118. }
  119.  
  120. void ScrollView::update(float dt)
  121. {
  122. auto pMoveNode = getTouchNode();
  123. if (pMoveNode == nullptr)
  124. {
  125. pMoveNode = getActiveNode();
  126. }
  127.  
  128. if (pMoveNode != nullptr)
  129. {
  130. auto nowOffset = pMoveNode->getPositionX();
  131. auto newOffset = nowOffset * 0.1f;
  132. if (!moveChilds(-newOffset))
  133. {
  134. pMoveNode = nullptr;
  135. }
  136. }
  137.  
  138. if (pMoveNode == nullptr)
  139. {
  140. stopUpdate();
  141. }
  142. }
  143.  
  144. bool ScrollView::moveChilds(float diff)
  145. {
  146. _offset += diff;
  147. auto scaleLength = _param.itemWidth * _param.scale / ;
  148. auto &childs = getChildren();
  149. ; i != childs.size(); ++i)
  150. {
  151. auto pChild = childs.at(i);
  152. auto offset = getNodeOffset(i);
  153. > _param.width)
  154. {
  155. pChild->setVisible(false);
  156. }
  157. else
  158. {
  159. auto newScale = ( - std::abs(offset) / getRight()) * _param.scale;
  160. ) newScale = ;
  161. if (newScale > _param.scale) newScale = _param.scale;
  162. pChild->setScale(newScale);
  163. pChild->setVisible(true);
  164. pChild->setPositionX(offset);
  165. if (isActive(i))
  166. {
  167. setActive(i);
  168. }
  169. }
  170. }
  171. return std::abs(diff) >= 0.1f;
  172. }
  173.  
  174. u_int ScrollView::getNodeIdx(const ccVec2 &worldPoint)
  175. {
  176. const auto &localPoint = convertToNodeSpace(worldPoint);
  177. const auto &childs = getChildren();
  178. ccRect rect;
  179. ; i != childs.size(); ++i)
  180. {
  181. rect.origin.x = getNodeOffset(i) - _param.itemWidth / ;
  182. rect.origin.y = -_param.anchorY * _param.itemHeight;
  183. rect.size.width = _param.itemWidth;
  184. rect.size.height = _param.itemHeight;
  185. if (rect.containsPoint(localPoint))
  186. {
  187. return i;
  188. }
  189. }
  190. return INVALID_VALUE;
  191. }

这么简洁且通俗易懂的代码, 我想就不用填注释了吧.

这个版本的实现思路要比原来的更简洁.

去掉了所谓的惯性控制对象,

去掉了N多变量,

优化了一些接口.

原来,

快速滑动会激发惯性, 当惯性停止时, 再调整位置, 这里用到2个定时器, 一个用于控制惯性, 一个用于调整位置;

单击锁定放在子节点的Touch里响应, 因此要注册很多EventListener;

没有直接锁定功能, 貌似因为设计的问题, 无法加上这个功能, 年代久远, 懒得考察;

以及一堆让现在的我无法忍受的代码.

现在,

取消单独定时器, 所有计时操作都在Node::update里处理, 节能减排;

单击锁定由一个EventListener处理, 节能减排;

可以直接锁定某个子节点;

两者最大的区别应该在于惯性的处理,

老板的根据滑动速度, 计算惯性速度, 然后等待惯性消失, 之后再调整位置, 这个过程很**.

新版的处理很巧妙, 通过滑动速度, 计算出将被锁定的节点, 之后直接锁定, 对接口的重用要好很多, 并且思路, 实现都很简洁.

下载 DEMO, 猛戳这里!!!

转载请注明出处!

cocos2dx 实现不一样的ScrollView的更多相关文章

  1. ‎Cocos2d-x 学习笔记(21.1) ScrollView “甩出”效果与 deaccelerateScrolling 方法

    1. 简介 “甩出”效果是当我们快速拖动container并松开后,container继续朝原方向运动,但是渐渐减速直到停止的效果. ScrollView的onTouchEnded方法会设置Timer ...

  2. 从零开始のcocos2dx生活(十)ScrollView

    目录 简介 基础变量 ScrollViewDelegate Direction _dragging _container _touchMoved _bounceable _touchLength 方法 ...

  3. 【Cocos2d-x】学习笔记目录

    从2019年7月开始学习游戏引擎Cocos2dx,版本3.17. 学习笔记尽量以白话的形式表达自己对源码的理解,而不是大篇幅复制粘贴源码. 本人水平有限,欢迎批评指正! Cocos2d-x 学习笔记 ...

  4. cocos2d-x ScrollView、TableView

    转自:http://codingnow.cn/cocos2d-x/1024.html 在游戏和应用中经常要实现左右滑动展示游戏帮助.以列表显示内容的UI效果,就像android中的Gallery和Li ...

  5. cocos2dx中的ScrollView

    ScrollView由视窗区域(裁剪区域)和内容区域组成,内容区域叫innerContainer. 视窗区域范围:get/setContentSize 内容区域:get/setInnerContain ...

  6. [cocos2dx]计算scrollview元素的index

    scrollview的原生代码没有提供元素对齐功能 通过下面介绍的index计算方法以及scrollview自带的设置位置方法 void setContentOffsetInDuration(CCPo ...

  7. Cocos2d-x 3.2 大富翁游戏项目开发-第五部分 单机游戏-级别选择ScrollView

    于MenuScene.cpp 点击单机游戏后会调用 Director::getInstance()->pushScene(MapChooseScene::createScene()); 进入到关 ...

  8. cocosStudio制作ScrollView并在cocos2dx 3.0中使用。

    使用cocosStudio制作界面基本已成为基础了,之前都是拖动一些 Image.Button的小控件,再用到层容器和滚动层的时候,习惯性的用拖动来改变控件的大小.但是你在把其他的控件拖动到上面的时候 ...

  9. cocos2dx 3.0 scrollview 在android下面背景變綠色了

    在windows上面跑的是OK的,  在android下面跑的時候就變成這樣子了:

随机推荐

  1. 在 slua 中使用更新的面向对象方案

    上一篇记录了我使用 Slua.Class 来实现面向对象扩展 C# 中得类,但实际使用中,更多地情况是直接在 lua 中定义基类然后扩展,于是触发了我重新思考下是否两种形式应该统一用一种,目前的方案中 ...

  2. Bzoj 2393: Cirno的完美算数教室 容斥原理,深搜

    2393: Cirno的完美算数教室 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 287  Solved: 175[Submit][Status][ ...

  3. QEMU MIPIS远程共享ubuntu主机的文件

    尝试啦很多中办法,最终选择以在QEMU模拟器中ssh 远程登入的方式访问主机,并用sshfs 挂载 主机端的文件到模拟器中,实现模拟器访问主机端的代码. SSH分客户端openssh-client和o ...

  4. git diff old mode 100755 new mode 100644

    755 vs 644 在linux下载了Qt的软件仓库,拷贝了一份到windows下.在 msysgit 下,发现所有的文件都被修改了. 用 git diff 查看,发现是: $ git diff u ...

  5. python中类的继承

    python中类的继承 在python中面向对象编程中实现继承,以下面一个实例进行说明. class SchoolMenber(): # __init__类似于c++中的构造函数 # __init__ ...

  6. 最短路SPFA

    用邻接矩阵a表示一幅图,a[i][j]表示从点i到点j的边长,如果为0则无边.(这是无负边,0边的情况) 这张图有T个点,C条边,要求求出从Ts走到Te的最短路. 用f[i]表示从Ts走到i点的最短路 ...

  7. InetAddress Example program in Java

    The InetAddress class has no visible constructors. To create an InetAddress object, you have to use ...

  8. Clojure学习资料

    以下大部分收藏自博客:http://blog.csdn.net/ithomer/article/details/17225813 官方文档: http://clojure.org/documentat ...

  9. 非常实用的PHP常用函数汇总

    这篇文章主要介绍了非常实用的PHP常用函数,汇总了加密解密.字符串操作.文件操作.SQL注入等函数的实例与用法说明,在PHP项目开发中非常具有实用价值,需要的朋友可以参考下 本文实例总结了一些在php ...

  10. (int),Convert.ToInt32(),Int32.Parse(),Int32.TryParsed()的用法总结

    1 (int) 强制转型为整型. 当将long,float,double,decimal等类型转换成int类型时可采用这种方式. double dblNum = 20; int intDblNum = ...