经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
?Cocos2d-x 学习笔记(21.1) ScrollView “甩出”效果与 deaccelerateScrolling 方法
来源:cnblogs  作者:深潮  时间:2019/8/23 8:32:51  对本文有异议

ScrollView的onTouchEnded方法会设置Timer,间隔0、延迟0、无限次数,回调函数是deaccelerateScrolling方法。说明触摸结束时,当该方法不被unschedule时将每帧执行一次。

deaccelerateScrolling方法中会判断ScrollView是否设置了回弹效果,我们先看有回弹的情况,对ScrollView不执行setContentSize时,maxInset和minInset均为0。

  1. if (_bounceable) //有回弹则true
  2. {
  3. maxInset = _maxInset;
  4. minInset = _minInset;
  5. }

接下来设置container位置,代码不再粘贴。

然后,该if语句第二第三个条件永远满足,那么将会执行unschedule,说明了deaccelerateScrolling将会只执行这一次。之后,当container此时超出范围时,再通过relocateContainer方法设置回弹效果,不再赘述。

  1. if (
  2. (fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST && fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST) ||
  3. ((_direction == Direction::BOTH || _direction == Direction::VERTICAL) && (newY >= maxInset.y || newY <= minInset.y)) ||
  4. ((_direction == Direction::BOTH || _direction == Direction::HORIZONTAL) && (newX >= maxInset.x || newX <= minInset.x))
  5. )
  6. {
  7. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::deaccelerateScrolling));
  8. this->relocateContainer(true);
  9. }

deaccelerateScrolling只执行一次,所以没有“甩出”效果。

刚才说的是有回弹且不执行setContentSize时deaccelerateScrolling方法大致流程。

当没有回弹时,maxInset和minInset被设置成container偏移范围的界限。

  1. if (_bounceable) //false
  2. {
  3. //...
  4. }
  5. else
  6. {
  7. maxInset = this->maxContainerOffset();
  8. minInset = this->minContainerOffset();
  9. }

那么,如果拖动在范围之内,接下来if判断的3个条件中后两个将为false,我们看第一个条件:

  1. (fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST && fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST)

_scrollDistance在if之前执行了:

  1. _scrollDistance = _scrollDistance * SCROLL_DEACCEL_RATE;

SCROLL_DEACCEL_DIST是一个界限,当_scrollDistance绝对值小于它时,使得if第一个条件满足,执行unschedule,deaccelerateScrolling将不会在下一帧执行。

onTouchMoved结束时保存了_scrollDistance,该向量是两次Moved之差。在触摸结束后,每帧执行deaccelerateScrolling时,_scrollDistance都会乘以小于0的系数SCROLL_DEACCEL_RATE,使得_scrollDistance渐渐变小。

并且,每次deaccelerateScrolling方法开始会根据当前_scrollDistance设置container的新位置:

  1. _container->setPosition(_container->getPosition() + _scrollDistance);

到这里,显而易见,虽然触摸结束了,但是deaccelerateScrolling将会在触摸结束后每帧执行,设置container的新位置,而每帧位置的增长都渐渐变小,实现了“甩动甩出”的效果。

当_scrollDistance小于界限值时,将会unschedule销毁Timer,deaccelerateScrolling不会在下一阵执行,我们看到的“甩出”效果就结束了。

还有一个问题,在无回弹情况下,如果“甩出”时container到了边界是如何处理的?

看deaccelerateScrolling部分代码:

  1. _container->setPosition(_container->getPosition() + _scrollDistance); //假设此时设置位置后越界
  2. if (_bounceable) //false
  3. {
  4. //...
  5. }
  6. else
  7. {
  8. maxInset = this->maxContainerOffset();
  9. minInset = this->minContainerOffset();
  10. }
  11. newX = _container->getPosition().x;
  12. newY = _container->getPosition().y;
  13. _scrollDistance = _scrollDistance * SCROLL_DEACCEL_RATE;
  14. this->setContentOffset(Vec2(newX,newY)); //

container在setPosition后又用setContentOffset方法设置了一次位置。

看setContentOffset部分代码:

  1. if (!_bounceable)
  2. {
  3. const Vec2 minOffset = this->minContainerOffset();
  4. const Vec2 maxOffset = this->maxContainerOffset();
  5. offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x));
  6. offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y));
  7. }
  8. _container->setPosition(offset);
  9. if (_delegate != nullptr)
  10. {
  11. _delegate->scrollViewDidScroll(this);
  12. }

当没有越界时,确实是执行了两次参数一样的setPosition。

越界时,位置会被修正为边界位置setPosition。

同时,因为修正前的坐标已经越界,deaccelerateScrolling方法最后会触发unschedule,“甩出”效果终止。

总结

设置了一个在触摸结束后每帧执行的Timer。对“甩出”时每帧之间container的距离间隔,在回调函数中设为比上一帧缩小,实现了速度慢慢减小,直到到达临界点停止。

原文链接:http://www.cnblogs.com/deepcho/p/cocos2dx-ccscrollview-deacceleratescrolling.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号