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下面跑的時候就變成這樣子了:
随机推荐
- [hadoop转载]tearsort
1TB排序通常用于衡量分布式数据处理框架的数据处理能力.Terasort是Hadoop中的的一个排序作业,在2008年,Hadoop在1TB排序基准评估中赢得第一名,耗时209秒.那么Tera ...
- POI2001 金矿
问题描述 金矿的老师傅年底要退休了.经理为了奖赏他的尽职尽责的工作,决定在一块包含 n(n ≤ 15000) 个采金点的长方形土地中划出一块长度为 S ,宽度为 W 的区域奖励给他(1 ≤ s , w ...
- poj 2503 字符串hash
题目链接:http://poj.org/problem?id=2503 代码: #include<cstdio> #include<cstring> #include<i ...
- 4 weekend110的hdfs下载数据源码跟踪铺垫 + hdfs下载数据源码分析-getFileSystem(值得反复推敲和打断点源码)
Hdfs下载数据源码分析 在这里,我是接着之前的,贴下代码 package cn.itcast.hadoop.hdfs; import java.io.FileInputStream; import ...
- Jquery Mobile左右滑动效果
首先在一个页面里面定义两个< div data-role="page">,这里为了突出重点,就没有写出footer和header.定义的页面如下: <body&g ...
- MVC中一般为什么用IQueryable而不是用IList
IList(IList<T>)会立即在内存里创建持久数据,这就没有实现“延期执行(deferred execution)”,如果被加载的实体有关联实体(associations),此关联实 ...
- linux文件的隐藏属性:chattr
1. 文件的隐藏属性 linux除了9个权限外,还有些隐藏属性, 使用chattr命令来设置. 使用方法: $ chattr +-=[ASacDdIijsTtu] + : 添加一个特殊參数 - : ...
- 将PL/SQL代码封装在机灵的包中
将代码封装在机灵的包中 http://www.oracle.com/technetwork/issue-archive/2013/13-jan/o13plsql-1872456.html 绝大多数基于 ...
- 恭贺自己itpub和csdn双双获得专家博客称号
这是对一个技术人员行业内很难得的认可,记录下来,加油...一切向钱看,明天会更好.
- careercup-数组和字符串1.6
1.6 给定一幅由N*N矩阵表示的如下,其中每个像素的大小为4个字节,编写一个方法,将图像旋转90度.不占用额外内存空间能否做到? 类似leetcode:Rotate Image 思路: 我们这里以逆 ...