cocos2dx 实现不一样的ScrollView
原来在公司被迫加班加点赶工,用lua实现的版本:http://www.cnblogs.com/mmc1206x/p/4146911.html
后来因我个人的需要, 用C++实现了一个版本.
蓦然回首, lua那版不忍直视, 设计拙劣, 代码拙劣, 当然, 这都归咎于那时的我太年轻.
效果图
ScrollView.h
- #pragma once
- #include "Base.h"
- class ScrollView : public ccNode {
- public:
- struct Param {
- float scale;
- float width;
- float height;
- float itemWidth;
- float itemHeight;
- float anchorY;
- std::function<void(ccNode *)> enterHandler;
- std::function<void(ccNode *)> leaveHandler;
- Param()
- : scale()
- , width()
- , height()
- , itemWidth()
- , itemHeight()
- , anchorY(0.5f)
- , enterHandler([](ccNode *){})
- , leaveHandler([](ccNode *){})
- {
- }
- };
- public:
- virtual void addChild(ccNode *pNode) override;
- virtual void removeChild(ccNode *pNode, bool cleanup = true) override;
- void gotoIndex(int index)
- {
- _touchIdx = index;
- runUpdate();
- }
- ccNode *getActiveNode()
- {
- return getNode(_activeIdx);
- }
- ccNode *getTouchNode()
- {
- return getNode(_touchIdx);
- }
- ccNode *getNode(u_int index)
- {
- auto &childs = getChildren();
- return index < (u_int)childs.size()
- ? childs.at(index) : nullptr;
- }
- float getNodeOffset(u_int index)
- {
- auto offset = getNodePos(index);
- auto max = getRight();
- auto min = getLeft();
- if (offset <= max && offset >= min)
- {
- offset -= (max - offset) * (_param.scale - );
- }
- else if (offset < min)
- {
- offset -= (max - min) * (_param.scale - );
- }
- return offset;
- }
- private:
- bool onTouchBegan(ccTouch *pTouch, ccEvent *pEvent);
- void onTouchMoved(ccTouch *pTouch, ccEvent *pEvent);
- void onTouchEnded(ccTouch *pTouch, ccEvent *pEvent);
- void onTouchCancelled(ccTouch *pTouch, ccEvent *pEvent);
- bool moveChilds(float diff);
- u_int getNodeIdx(const ccVec2 &worldPoint);
- virtual void update(float dt) override;
- void setActive(u_int index)
- {
- auto pOldNode = getActiveNode();
- auto pNewNode = getNode(index);
- MMC_ASSERT(pNewNode != nullptr);
- if (pOldNode != pNewNode)
- {
- _activeIdx = index;
- if (pOldNode != nullptr)
- {
- _param.leaveHandler(pOldNode);
- }
- _param.enterHandler(pNewNode);
- }
- }
- private:
- float getNodePos(u_int index)
- {
- return _param.itemWidth * index + _offset;
- }
- float getRight()
- {
- ;
- }
- float getLeft()
- {
- return getRight() - _param.itemWidth;
- }
- bool isActive(u_int index)
- {
- auto offset = getNodePos(index);
- return offset <= getRight() && offset >= getLeft();
- }
- void stopUpdate()
- {
- unscheduleUpdate();
- }
- void runUpdate()
- {
- scheduleUpdate();
- }
- private:
- ScrollView();
- ~ScrollView();
- void mmcInit(const Param ¶m);
- friend ScrollView *utils::createCocos<ScrollView>(const Param &);
- private:
- ccEventListenerTouchOneByOne *_listener;
- Param _param;
- float _offset;
- int _activeIdx;
- int _touchIdx;
- int _tick;
- };
ScrollView.cpp
- #include "ScrollView.h"
- ScrollView::ScrollView()
- : _listener(nullptr)
- , _activeIdx(INVALID_VALUE)
- , _touchIdx(INVALID_VALUE)
- , _offset()
- {
- }
- ScrollView::~ScrollView()
- {
- }
- void ScrollView::mmcInit(const Param ¶m)
- {
- if (!Node::init())
- {
- MMC_ASSERT(false);
- }
- _listener = ccEventListenerTouchOneByOne::create();
- _listener->onTouchBegan = CC_CALLBACK_2(ScrollView::onTouchBegan, this);
- _listener->onTouchMoved = CC_CALLBACK_2(ScrollView::onTouchMoved, this);
- _listener->onTouchEnded = CC_CALLBACK_2(ScrollView::onTouchEnded, this);
- _listener->onTouchCancelled = CC_CALLBACK_2(ScrollView::onTouchCancelled, this);
- _listener->setSwallowTouches(true);
- getEventDispatcher()->addEventListenerWithSceneGraphPriority(_listener, this);
- _offset = ;
- _param = param;
- runUpdate();
- }
- void ScrollView::addChild(ccNode *pNode)
- {
- auto childCount = getChildrenCount();
- auto offset = getNodeOffset(childCount);
- pNode->setPositionX(offset);
- pNode->setAnchorPoint(ccVec2(0.5f, _param.anchorY));
- if (_activeIdx == INVALID_VALUE && _touchIdx == INVALID_VALUE)
- {
- _touchIdx = childCount;
- runUpdate();
- }
- Node::addChild(pNode);
- }
- void ScrollView::removeChild(Node *pNode, bool cleanup)
- {
- auto pActive = getActiveNode();
- if (pActive == pNode)
- {
- _activeIdx = INVALID_VALUE;
- }
- auto pTouch = getTouchNode();
- if (pTouch == pNode)
- {
- _touchIdx = INVALID_VALUE;
- }
- Node::removeChild(pNode, cleanup);
- }
- bool ScrollView::onTouchBegan(ccTouch *pTouch, ccEvent *pEvent)
- {
- const auto &size = getContentSize();
- const auto &touchRect = ccRect(
- _param.width * -0.5f,
- _param.height * -_param.anchorY,
- _param.width, _param.height);
- const auto &worldPoint = pTouch->getLocation();
- const auto &localPoint = convertToNodeSpace(worldPoint);
- auto isTouch = touchRect.containsPoint(localPoint);
- if (isTouch)
- {
- _tick = clock();
- stopUpdate();
- }
- return isTouch;
- }
- void ScrollView::onTouchMoved(ccTouch *pTouch, ccEvent *pEvent)
- {
- auto diffOffset = pTouch->getDelta().x;
- auto nowtick = clock();
- auto difftick = nowtick - _tick;
- #ifdef WIN32
- ;
- #else
- / ;
- #endif
- _tick = nowtick;
- _touchIdx = _activeIdx - offsetIndex;
- if (_touchIdx >= getChildrenCount())
- {
- _touchIdx = getChildrenCount() - ;
- }
- )
- {
- _touchIdx = ;
- }
- moveChilds(diffOffset);
- }
- void ScrollView::onTouchEnded(ccTouch *pTouch, ccEvent *pEvent)
- {
- const auto &beg = pTouch->getStartLocation();
- const auto &end = pTouch->getLocation();
- const auto &delta = beg.getDistance(end);
- )
- {
- _touchIdx = getNodeIdx(end);
- }
- runUpdate();
- }
- void ScrollView::onTouchCancelled(ccTouch *pTouch, ccEvent *pEvent)
- {
- }
- void ScrollView::update(float dt)
- {
- auto pMoveNode = getTouchNode();
- if (pMoveNode == nullptr)
- {
- pMoveNode = getActiveNode();
- }
- if (pMoveNode != nullptr)
- {
- auto nowOffset = pMoveNode->getPositionX();
- auto newOffset = nowOffset * 0.1f;
- if (!moveChilds(-newOffset))
- {
- pMoveNode = nullptr;
- }
- }
- if (pMoveNode == nullptr)
- {
- stopUpdate();
- }
- }
- bool ScrollView::moveChilds(float diff)
- {
- _offset += diff;
- auto scaleLength = _param.itemWidth * _param.scale / ;
- auto &childs = getChildren();
- ; i != childs.size(); ++i)
- {
- auto pChild = childs.at(i);
- auto offset = getNodeOffset(i);
- > _param.width)
- {
- pChild->setVisible(false);
- }
- else
- {
- auto newScale = ( - std::abs(offset) / getRight()) * _param.scale;
- ) newScale = ;
- if (newScale > _param.scale) newScale = _param.scale;
- pChild->setScale(newScale);
- pChild->setVisible(true);
- pChild->setPositionX(offset);
- if (isActive(i))
- {
- setActive(i);
- }
- }
- }
- return std::abs(diff) >= 0.1f;
- }
- u_int ScrollView::getNodeIdx(const ccVec2 &worldPoint)
- {
- const auto &localPoint = convertToNodeSpace(worldPoint);
- const auto &childs = getChildren();
- ccRect rect;
- ; i != childs.size(); ++i)
- {
- rect.origin.x = getNodeOffset(i) - _param.itemWidth / ;
- rect.origin.y = -_param.anchorY * _param.itemHeight;
- rect.size.width = _param.itemWidth;
- rect.size.height = _param.itemHeight;
- if (rect.containsPoint(localPoint))
- {
- return i;
- }
- }
- return INVALID_VALUE;
- }
这么简洁且通俗易懂的代码, 我想就不用填注释了吧.
这个版本的实现思路要比原来的更简洁.
去掉了所谓的惯性控制对象,
去掉了N多变量,
优化了一些接口.
原来,
快速滑动会激发惯性, 当惯性停止时, 再调整位置, 这里用到2个定时器, 一个用于控制惯性, 一个用于调整位置;
单击锁定放在子节点的Touch里响应, 因此要注册很多EventListener;
没有直接锁定功能, 貌似因为设计的问题, 无法加上这个功能, 年代久远, 懒得考察;
以及一堆让现在的我无法忍受的代码.
现在,
取消单独定时器, 所有计时操作都在Node::update里处理, 节能减排;
单击锁定由一个EventListener处理, 节能减排;
可以直接锁定某个子节点;
两者最大的区别应该在于惯性的处理,
老板的根据滑动速度, 计算惯性速度, 然后等待惯性消失, 之后再调整位置, 这个过程很**.
新版的处理很巧妙, 通过滑动速度, 计算出将被锁定的节点, 之后直接锁定, 对接口的重用要好很多, 并且思路, 实现都很简洁.
转载请注明出处!
cocos2dx 实现不一样的ScrollView的更多相关文章
- Cocos2d-x 学习笔记(21.1) ScrollView “甩出”效果与 deaccelerateScrolling 方法
1. 简介 “甩出”效果是当我们快速拖动container并松开后,container继续朝原方向运动,但是渐渐减速直到停止的效果. ScrollView的onTouchEnded方法会设置Timer ...
- 从零开始のcocos2dx生活(十)ScrollView
目录 简介 基础变量 ScrollViewDelegate Direction _dragging _container _touchMoved _bounceable _touchLength 方法 ...
- 【Cocos2d-x】学习笔记目录
从2019年7月开始学习游戏引擎Cocos2dx,版本3.17. 学习笔记尽量以白话的形式表达自己对源码的理解,而不是大篇幅复制粘贴源码. 本人水平有限,欢迎批评指正! Cocos2d-x 学习笔记 ...
- cocos2d-x ScrollView、TableView
转自:http://codingnow.cn/cocos2d-x/1024.html 在游戏和应用中经常要实现左右滑动展示游戏帮助.以列表显示内容的UI效果,就像android中的Gallery和Li ...
- cocos2dx中的ScrollView
ScrollView由视窗区域(裁剪区域)和内容区域组成,内容区域叫innerContainer. 视窗区域范围:get/setContentSize 内容区域:get/setInnerContain ...
- [cocos2dx]计算scrollview元素的index
scrollview的原生代码没有提供元素对齐功能 通过下面介绍的index计算方法以及scrollview自带的设置位置方法 void setContentOffsetInDuration(CCPo ...
- Cocos2d-x 3.2 大富翁游戏项目开发-第五部分 单机游戏-级别选择ScrollView
于MenuScene.cpp 点击单机游戏后会调用 Director::getInstance()->pushScene(MapChooseScene::createScene()); 进入到关 ...
- cocosStudio制作ScrollView并在cocos2dx 3.0中使用。
使用cocosStudio制作界面基本已成为基础了,之前都是拖动一些 Image.Button的小控件,再用到层容器和滚动层的时候,习惯性的用拖动来改变控件的大小.但是你在把其他的控件拖动到上面的时候 ...
- cocos2dx 3.0 scrollview 在android下面背景變綠色了
在windows上面跑的是OK的, 在android下面跑的時候就變成這樣子了:
随机推荐
- 在 slua 中使用更新的面向对象方案
上一篇记录了我使用 Slua.Class 来实现面向对象扩展 C# 中得类,但实际使用中,更多地情况是直接在 lua 中定义基类然后扩展,于是触发了我重新思考下是否两种形式应该统一用一种,目前的方案中 ...
- Bzoj 2393: Cirno的完美算数教室 容斥原理,深搜
2393: Cirno的完美算数教室 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 287 Solved: 175[Submit][Status][ ...
- QEMU MIPIS远程共享ubuntu主机的文件
尝试啦很多中办法,最终选择以在QEMU模拟器中ssh 远程登入的方式访问主机,并用sshfs 挂载 主机端的文件到模拟器中,实现模拟器访问主机端的代码. SSH分客户端openssh-client和o ...
- git diff old mode 100755 new mode 100644
755 vs 644 在linux下载了Qt的软件仓库,拷贝了一份到windows下.在 msysgit 下,发现所有的文件都被修改了. 用 git diff 查看,发现是: $ git diff u ...
- python中类的继承
python中类的继承 在python中面向对象编程中实现继承,以下面一个实例进行说明. class SchoolMenber(): # __init__类似于c++中的构造函数 # __init__ ...
- 最短路SPFA
用邻接矩阵a表示一幅图,a[i][j]表示从点i到点j的边长,如果为0则无边.(这是无负边,0边的情况) 这张图有T个点,C条边,要求求出从Ts走到Te的最短路. 用f[i]表示从Ts走到i点的最短路 ...
- InetAddress Example program in Java
The InetAddress class has no visible constructors. To create an InetAddress object, you have to use ...
- Clojure学习资料
以下大部分收藏自博客:http://blog.csdn.net/ithomer/article/details/17225813 官方文档: http://clojure.org/documentat ...
- 非常实用的PHP常用函数汇总
这篇文章主要介绍了非常实用的PHP常用函数,汇总了加密解密.字符串操作.文件操作.SQL注入等函数的实例与用法说明,在PHP项目开发中非常具有实用价值,需要的朋友可以参考下 本文实例总结了一些在php ...
- (int),Convert.ToInt32(),Int32.Parse(),Int32.TryParsed()的用法总结
1 (int) 强制转型为整型. 当将long,float,double,decimal等类型转换成int类型时可采用这种方式. double dblNum = 20; int intDblNum = ...