CCScrollViewSmooth.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  1. /****************************************************************************
  2. Copyright (c) 2012 cocos2d-x.org
  3. Copyright (c) 2010 Sangwoo Im
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. #include "CCScrollViewSmooth.h"
  22. #include "platform/CCDevice.h"
  23. #include "2d/CCActionInstant.h"
  24. #include "2d/CCActionInterval.h"
  25. #include "2d/CCActionTween.h"
  26. #include "base/CCDirector.h"
  27. #include "base/CCEventDispatcher.h"
  28. #include "renderer/CCRenderer.h"
  29. #include "base/ccUtils.h"
  30. #include "2d/CCTweenFunction.h"
  31. #include <algorithm>
  32. NS_CC_EXT_BEGIN
  33. #define SCROLL_DEACCEL_RATE 0.95f
  34. #define SCROLL_DEACCEL_DIST 1.0f
  35. #define BOUNCE_DURATION 0.15f
  36. #define INSET_RATIO 0.2f
  37. #define MOVE_INCH 7.0f/160.0f
  38. #define BOUNCE_BACK_FACTOR 0.35f
  39. //zg
  40. #define TURN_PAGE_SPEED 0.20f //designPixl/ms
  41. #define INVALID_PAGE 0xfff
  42. #define TURN_PAGE_MIN_OFFSET_RATIO 0.1f
  43. static float convertDistanceFromPointToInch(float pointDis)
  44. {
  45. auto glview = Director::getInstance()->getOpenGLView();
  46. float factor = ( glview->getScaleX() + glview->getScaleY() ) / 2;
  47. return pointDis * factor / Device::getDPI();
  48. }
  49. ScrollViewSmooth::ScrollViewSmooth()
  50. : _delegate(nullptr)
  51. , _direction(Direction::BOTH)
  52. , _dragging(false)
  53. , _container(nullptr)
  54. , _touchMoved(false)
  55. , _bounceable(false)
  56. , _clippingToBounds(false)
  57. , _touchLength(0.0f)
  58. , _minScale(0.0f)
  59. , _maxScale(0.0f)
  60. , _scissorRestored(false)
  61. , _touchListener(nullptr)
  62. , _animatedScrollAction(nullptr)
  63. ,_autoScrollCurrentlyOutOfBoundary(false)
  64. ,_autoScrollBraking(false)
  65. // zg
  66. , m_bPaged(false)
  67. , m_currPage(0)
  68. , m_targetPage(INVALID_PAGE)
  69. , m_touchBeganTime(0)
  70. , m_touchBeganOffset(0)
  71. , m_pageAdjustSize(Size::ZERO)
  72. , m_bIsScrollingPaused(false)
  73. // zml
  74. , _isInterceptTouch(false)
  75. , _bePressed(false)
  76. , _autoScrolling(false)
  77. , _autoScrollTotalTime(0)
  78. , _autoScrollAccumulatedTime(0)
  79. , _touchMovePreviousTimestamp(0)
  80. {
  81. }
  82. ScrollViewSmooth::~ScrollViewSmooth()
  83. {
  84. }
  85. ScrollViewSmooth* ScrollViewSmooth::create(Size size, Node* container/* = nullptr*/)
  86. {
  87. ScrollViewSmooth* pRet = new (std::nothrow) ScrollViewSmooth();
  88. if (pRet && pRet->initWithViewSize(size, container))
  89. {
  90. pRet->autorelease();
  91. }
  92. else
  93. {
  94. CC_SAFE_DELETE(pRet);
  95. }
  96. return pRet;
  97. }
  98. ScrollViewSmooth* ScrollViewSmooth::create()
  99. {
  100. ScrollViewSmooth* pRet = new (std::nothrow) ScrollViewSmooth();
  101. if (pRet && pRet->init())
  102. {
  103. pRet->autorelease();
  104. }
  105. else
  106. {
  107. CC_SAFE_DELETE(pRet);
  108. }
  109. return pRet;
  110. }
  111. bool ScrollViewSmooth::initWithViewSize(Size size, Node *container/* = nullptr*/)
  112. {
  113. if (Layer::init())
  114. {
  115. _container = container;
  116. if (!this->_container)
  117. {
  118. _container = Layer::create();
  119. _container->setIgnoreAnchorPointForPosition(false);
  120. _container->setAnchorPoint(Vec2(0.0f, 0.0f));
  121. }
  122. this->setViewSize(size);
  123. setTouchEnabled(true);
  124. _touches.reserve(EventTouch::MAX_TOUCHES);
  125. _delegate = nullptr;
  126. _bounceable = true;
  127. _clippingToBounds = true;
  128. //_container->setContentSize(Size::ZERO);
  129. _direction = Direction::BOTH;
  130. _container->setPosition(0.0f, 0.0f);
  131. _touchLength = 0.0f;
  132. this->addChild(_container);
  133. _minScale = _maxScale = 1.0f;
  134. return true;
  135. }
  136. return false;
  137. }
  138. bool ScrollViewSmooth::init()
  139. {
  140. return this->initWithViewSize(Size(200, 200), nullptr);
  141. }
  142. bool ScrollViewSmooth::isNodeVisible(Node* node)
  143. {
  144. const Vec2 offset = this->getContentOffset();
  145. const Size size = this->getViewSize();
  146. const float scale = this->getZoomScale();
  147. Rect viewRect;
  148. viewRect = Rect(-offset.x/scale, -offset.y/scale, size.width/scale, size.height/scale);
  149. return viewRect.intersectsRect(node->getBoundingBox());
  150. }
  151. void ScrollViewSmooth::pause(Ref* /*sender*/)
  152. {
  153. _container->pause();
  154. auto& children = _container->getChildren();
  155. for(const auto &child : children) {
  156. child->pause();
  157. }
  158. }
  159. void ScrollViewSmooth::resume(Ref* /*sender*/)
  160. {
  161. auto& children = _container->getChildren();
  162. for(const auto &child : children) {
  163. child->resume();
  164. }
  165. _container->resume();
  166. }
  167. bool ScrollViewSmooth::isTouchEnabled() const
  168. {
  169. return _touchListener != nullptr;
  170. }
  171. void ScrollViewSmooth::setTouchEnabled(bool enabled)
  172. {
  173. _eventDispatcher->removeEventListener(_touchListener);
  174. _touchListener = nullptr;
  175. if (enabled)
  176. {
  177. _touchListener = EventListenerTouchOneByOne::create();
  178. _touchListener->setSwallowTouches(true);
  179. _touchListener->onTouchBegan = CC_CALLBACK_2(ScrollViewSmooth::onTouchBegan, this);
  180. _touchListener->onTouchMoved = CC_CALLBACK_2(ScrollViewSmooth::onTouchMoved, this);
  181. _touchListener->onTouchEnded = CC_CALLBACK_2(ScrollViewSmooth::onTouchEnded, this);
  182. _touchListener->onTouchCancelled = CC_CALLBACK_2(ScrollViewSmooth::onTouchCancelled, this);
  183. _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
  184. }
  185. else
  186. {
  187. _dragging = false;
  188. _touchMoved = false;
  189. _touches.clear();
  190. }
  191. }
  192. void ScrollViewSmooth::setContentOffset(Vec2 offset, bool animated/* = false*/)
  193. {
  194. if (animated)
  195. { //animate scrolling
  196. this->setContentOffsetInDuration(offset, BOUNCE_DURATION);
  197. }
  198. else
  199. { //set the container position directly
  200. if (!_bounceable)
  201. {
  202. const Vec2 minOffset = this->minContainerOffset();
  203. const Vec2 maxOffset = this->maxContainerOffset();
  204. offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x));
  205. offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y));
  206. }
  207. _container->setPosition(offset);
  208. if (_delegate != nullptr)
  209. {
  210. _delegate->scrollViewDidScroll(this);
  211. }
  212. }
  213. }
  214. void ScrollViewSmooth::setContentOffsetInDuration(Vec2 offset, float dt)
  215. {
  216. FiniteTimeAction *scroll, *expire;
  217. if (_animatedScrollAction) {
  218. stopAnimatedContentOffset();
  219. }
  220. scroll = MoveTo::create(dt, offset);
  221. expire = CallFuncN::create(CC_CALLBACK_1(ScrollViewSmooth::stoppedAnimatedScroll,this));
  222. _animatedScrollAction = _container->runAction(Sequence::create(scroll, expire, nullptr));
  223. _animatedScrollAction->retain();
  224. this->schedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::performedAnimatedScroll));
  225. }
  226. void ScrollViewSmooth::stopAnimatedContentOffset() {
  227. stopAction(_animatedScrollAction);
  228. _animatedScrollAction->release();
  229. _animatedScrollAction = nullptr;
  230. stoppedAnimatedScroll(this);
  231. }
  232. Vec2 ScrollViewSmooth::getContentOffset()
  233. {
  234. return _container->getPosition();
  235. }
  236. void ScrollViewSmooth::setZoomScale(float s)
  237. {
  238. if (_container->getScale() != s)
  239. {
  240. Vec2 oldCenter, newCenter;
  241. Vec2 center;
  242. if (_touchLength == 0.0f)
  243. {
  244. center.set(_viewSize.width*0.5f, _viewSize.height*0.5f);
  245. center = this->convertToWorldSpace(center);
  246. }
  247. else
  248. {
  249. center = _touchPoint;
  250. }
  251. oldCenter = _container->convertToNodeSpace(center);
  252. _container->setScale(MAX(_minScale, MIN(_maxScale, s)));
  253. newCenter = _container->convertToWorldSpace(oldCenter);
  254. const Vec2 offset = center - newCenter;
  255. if (_delegate != nullptr)
  256. {
  257. _delegate->scrollViewDidZoom(this);
  258. }
  259. this->setContentOffset(_container->getPosition() + offset);
  260. }
  261. }
  262. float ScrollViewSmooth::getZoomScale()
  263. {
  264. return _container->getScale();
  265. }
  266. void ScrollViewSmooth::setZoomScale(float s, bool animated)
  267. {
  268. if (animated)
  269. {
  270. this->setZoomScaleInDuration(s, BOUNCE_DURATION);
  271. }
  272. else
  273. {
  274. this->setZoomScale(s);
  275. }
  276. }
  277. void ScrollViewSmooth::setZoomScaleInDuration(float s, float dt)
  278. {
  279. if (dt > 0)
  280. {
  281. if (_container->getScale() != s)
  282. {
  283. ActionTween *scaleAction;
  284. scaleAction = ActionTween::create(dt, "zoomScale", _container->getScale(), s);
  285. this->runAction(scaleAction);
  286. }
  287. }
  288. else
  289. {
  290. this->setZoomScale(s);
  291. }
  292. }
  293. void ScrollViewSmooth::updateTweenAction(float value, const std::string& /*key*/)
  294. {
  295. this->setZoomScale(value);
  296. }
  297. void ScrollViewSmooth::setViewSize(Size size)
  298. {
  299. _viewSize = size;
  300. Layer::setContentSize(size);
  301. }
  302. Node * ScrollViewSmooth::getContainer()
  303. {
  304. return this->_container;
  305. }
  306. void ScrollViewSmooth::setContainer(Node * pContainer)
  307. {
  308. // Make sure that '_container' has a non-nullptr value since there are
  309. // lots of logic that use '_container'.
  310. if (nullptr == pContainer)
  311. return;
  312. this->removeAllChildrenWithCleanup(true);
  313. this->_container = pContainer;
  314. this->_container->setIgnoreAnchorPointForPosition(false);
  315. this->_container->setAnchorPoint(Vec2(0.0f, 0.0f));
  316. this->addChild(this->_container);
  317. this->setViewSize(this->_viewSize);
  318. }
  319. bool ScrollViewSmooth::hasVisibleParents() const
  320. {
  321. auto parent = this->getParent();
  322. for( auto c = parent; c != nullptr; c = c->getParent() )
  323. {
  324. if( !c->isVisible() )
  325. {
  326. return false;
  327. }
  328. }
  329. return true;
  330. }
  331. void ScrollViewSmooth::relocateContainer(bool animated)
  332. {
  333. Vec2 oldPoint, min, max;
  334. float newX, newY;
  335. min = this->minContainerOffset();
  336. max = this->maxContainerOffset();
  337. oldPoint = _container->getPosition();
  338. newX = oldPoint.x;
  339. newY = oldPoint.y;
  340. if (_direction == Direction::BOTH || _direction == Direction::HORIZONTAL)
  341. {
  342. newX = MAX(newX, min.x);
  343. newX = MIN(newX, max.x);
  344. }
  345. if (_direction == Direction::BOTH || _direction == Direction::VERTICAL)
  346. {
  347. newY = MIN(newY, max.y);
  348. newY = MAX(newY, min.y);
  349. }
  350. if (newY != oldPoint.y || newX != oldPoint.x)
  351. {
  352. this->setContentOffset(Vec2(newX, newY), animated);
  353. }
  354. }
  355. Vec2 ScrollViewSmooth::maxContainerOffset()
  356. {
  357. Point anchorPoint = _container->isIgnoreAnchorPointForPosition()?Point::ZERO:_container->getAnchorPoint();
  358. float contW = _container->getContentSize().width * _container->getScaleX();
  359. float contH = _container->getContentSize().height * _container->getScaleY();
  360. return Vec2(anchorPoint.x * contW, anchorPoint.y * contH);
  361. }
  362. Vec2 ScrollViewSmooth::minContainerOffset()
  363. {
  364. Point anchorPoint = _container->isIgnoreAnchorPointForPosition()?Point::ZERO:_container->getAnchorPoint();
  365. float contW = _container->getContentSize().width * _container->getScaleX();
  366. float contH = _container->getContentSize().height * _container->getScaleY();
  367. return Vec2(_viewSize.width - (1 - anchorPoint.x) * contW, _viewSize.height - (1 - anchorPoint.y) * contH);
  368. }
  369. void ScrollViewSmooth::deaccelerateScrolling(float /*dt*/)
  370. {
  371. if (_dragging)
  372. {
  373. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::deaccelerateScrolling));
  374. return;
  375. }
  376. float newX, newY;
  377. Vec2 maxInset, minInset;
  378. _container->setPosition(_container->getPosition() + _scrollDistance);
  379. if (_bounceable)
  380. {
  381. maxInset = _maxInset;
  382. minInset = _minInset;
  383. }
  384. else
  385. {
  386. maxInset = this->maxContainerOffset();
  387. minInset = this->minContainerOffset();
  388. }
  389. newX = _container->getPosition().x;
  390. newY = _container->getPosition().y;
  391. _scrollDistance = _scrollDistance * SCROLL_DEACCEL_RATE;
  392. this->setContentOffset(Vec2(newX,newY));
  393. if ((fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST &&
  394. fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST) ||
  395. ((_direction == Direction::BOTH || _direction == Direction::VERTICAL) && (newY >= maxInset.y || newY <= minInset.y)) ||
  396. ((_direction == Direction::BOTH || _direction == Direction::HORIZONTAL) && (newX >= maxInset.x || newX <= minInset.x)))
  397. {
  398. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::deaccelerateScrolling));
  399. this->relocateContainer(true);
  400. }
  401. }
  402. void ScrollViewSmooth::stoppedAnimatedScroll(Node * /*node*/)
  403. {
  404. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::performedAnimatedScroll));
  405. // After the animation stopped, "scrollViewDidScroll" should be invoked, this could fix the bug of lack of tableview cells.
  406. if (_delegate != nullptr)
  407. {
  408. _delegate->scrollViewDidScroll(this);
  409. }
  410. }
  411. void ScrollViewSmooth::performedAnimatedScroll(float /*dt*/)
  412. {
  413. if (_dragging)
  414. {
  415. this->unschedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::performedAnimatedScroll));
  416. return;
  417. }
  418. if (_delegate != nullptr)
  419. {
  420. _delegate->scrollViewDidScroll(this);
  421. }
  422. }
  423. const Size& ScrollViewSmooth::getContentSize() const
  424. {
  425. return _container->getContentSize();
  426. }
  427. void ScrollViewSmooth::setContentSize(const Size & size)
  428. {
  429. if (this->getContainer() != nullptr)
  430. {
  431. this->getContainer()->setContentSize(size);
  432. this->updateInset();
  433. }
  434. }
  435. void ScrollViewSmooth::updateInset()
  436. {
  437. if (this->getContainer() != nullptr)
  438. {
  439. _maxInset = this->maxContainerOffset();
  440. _maxInset.set(_maxInset.x + _viewSize.width * INSET_RATIO,
  441. _maxInset.y + _viewSize.height * INSET_RATIO);
  442. _minInset = this->minContainerOffset();
  443. _minInset.set(_minInset.x - _viewSize.width * INSET_RATIO,
  444. _minInset.y - _viewSize.height * INSET_RATIO);
  445. }
  446. }
  447. /**
  448. * make sure all children go to the container
  449. */
  450. void ScrollViewSmooth::addChild(Node * child, int zOrder, int tag)
  451. {
  452. if (_container != child) {
  453. _container->addChild(child, zOrder, tag);
  454. } else {
  455. Layer::addChild(child, zOrder, tag);
  456. }
  457. }
  458. void ScrollViewSmooth::removeChild(Node* node, bool cleanup)
  459. {
  460. if(_container != node)
  461. {
  462. _container->removeChild(node, cleanup);
  463. }
  464. else
  465. {
  466. Layer::removeChild(node, cleanup);
  467. }
  468. }
  469. void ScrollViewSmooth::removeAllChildrenWithCleanup(bool cleanup)
  470. {
  471. _container->removeAllChildrenWithCleanup(cleanup);
  472. Layer::removeAllChildrenWithCleanup(cleanup);
  473. }
  474. void ScrollViewSmooth::removeAllChildren()
  475. {
  476. removeAllChildrenWithCleanup(true);
  477. }
  478. void ScrollViewSmooth::addChild(Node * child, int zOrder, const std::string &name)
  479. {
  480. if (_container != child)
  481. {
  482. _container->addChild(child, zOrder, name);
  483. }
  484. else
  485. {
  486. Layer::addChild(child, zOrder, name);
  487. }
  488. }
  489. void ScrollViewSmooth::beforeDraw()
  490. {
  491. //ScrollView don't support drawing in 3D space
  492. _beforeDrawCommand.init(_globalZOrder);
  493. _beforeDrawCommand.func = CC_CALLBACK_0(ScrollViewSmooth::onBeforeDraw, this);
  494. Director::getInstance()->getRenderer()->addCommand(&_beforeDrawCommand);
  495. }
  496. /**
  497. * clip this view so that outside of the visible bounds can be hidden.
  498. */
  499. void ScrollViewSmooth::onBeforeDraw()
  500. {
  501. if (_clippingToBounds)
  502. {
  503. _scissorRestored = false;
  504. Rect frame = getViewRect();
  505. auto glview = Director::getInstance()->getOpenGLView();
  506. if (glview->getVR() == nullptr) {
  507. if (glview->isScissorEnabled()) {
  508. _scissorRestored = true;
  509. _parentScissorRect = glview->getScissorRect();
  510. //set the intersection of _parentScissorRect and frame as the new scissor rect
  511. if (frame.intersectsRect(_parentScissorRect)) {
  512. float x = MAX(frame.origin.x, _parentScissorRect.origin.x);
  513. float y = MAX(frame.origin.y, _parentScissorRect.origin.y);
  514. float xx = MIN(frame.origin.x + frame.size.width, _parentScissorRect.origin.x + _parentScissorRect.size.width);
  515. float yy = MIN(frame.origin.y + frame.size.height, _parentScissorRect.origin.y + _parentScissorRect.size.height);
  516. glview->setScissorInPoints(x, y, xx - x, yy - y);
  517. }
  518. }
  519. else {
  520. glEnable(GL_SCISSOR_TEST);
  521. glview->setScissorInPoints(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
  522. }
  523. }
  524. }
  525. }
  526. void ScrollViewSmooth::afterDraw()
  527. {
  528. _afterDrawCommand.init(_globalZOrder);
  529. _afterDrawCommand.func = CC_CALLBACK_0(ScrollViewSmooth::onAfterDraw, this);
  530. Director::getInstance()->getRenderer()->addCommand(&_afterDrawCommand);
  531. }
  532. /**
  533. * retract what's done in beforeDraw so that there's no side effect to
  534. * other nodes.
  535. */
  536. void ScrollViewSmooth::onAfterDraw()
  537. {
  538. if (_clippingToBounds)
  539. {
  540. auto glview = Director::getInstance()->getOpenGLView();
  541. if (glview->getVR() == nullptr) {
  542. if (_scissorRestored) {//restore the parent's scissor rect
  543. glview->setScissorInPoints(_parentScissorRect.origin.x, _parentScissorRect.origin.y, _parentScissorRect.size.width, _parentScissorRect.size.height);
  544. }
  545. else {
  546. glDisable(GL_SCISSOR_TEST);
  547. }
  548. }
  549. }
  550. }
  551. void ScrollViewSmooth::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
  552. {
  553. // quick return if not visible
  554. if (!isVisible())
  555. {
  556. return;
  557. }
  558. uint32_t flags = processParentFlags(parentTransform, parentFlags);
  559. // IMPORTANT:
  560. // To ease the migration to v3.0, we still support the Mat4 stack,
  561. // but it is deprecated and your code should not rely on it
  562. Director* director = Director::getInstance();
  563. CCASSERT(nullptr != director, "Director is null when setting matrix stack");
  564. director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  565. director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
  566. this->beforeDraw();
  567. bool visibleByCamera = isVisitableByVisitingCamera();
  568. if (!_children.empty())
  569. {
  570. int i=0;
  571. // draw children zOrder < 0
  572. for( ; i < _children.size(); i++ )
  573. {
  574. Node *child = _children.at(i);
  575. if ( child->getLocalZOrder() < 0 )
  576. {
  577. child->visit(renderer, _modelViewTransform, flags);
  578. }
  579. else
  580. {
  581. break;
  582. }
  583. }
  584. // this draw
  585. if (visibleByCamera)
  586. this->draw(renderer, _modelViewTransform, flags);
  587. // draw children zOrder >= 0
  588. for( ; i < _children.size(); i++ )
  589. {
  590. Node *child = _children.at(i);
  591. child->visit(renderer, _modelViewTransform, flags);
  592. }
  593. }
  594. else if (visibleByCamera)
  595. {
  596. this->draw(renderer, _modelViewTransform, flags);
  597. }
  598. this->afterDraw();
  599. director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  600. }
  601. bool ScrollViewSmooth::onTouchBegan(Touch* touch, Event* /*event*/)
  602. {
  603. /*
  604. if (!this->isVisible() || !this->hasVisibleParents())
  605. {
  606. return false;
  607. }
  608. Rect frame = getViewRect();
  609. //dispatcher does not know about clipping. reject touches outside visible bounds.
  610. if (_touches.size() > 2 ||
  611. _touchMoved ||
  612. !frame.containsPoint(touch->getLocation()))
  613. {
  614. return false;
  615. }
  616. if (std::find(_touches.begin(), _touches.end(), touch) == _touches.end())
  617. {
  618. _touches.push_back(touch);
  619. }
  620. if (_touches.size() == 1)
  621. { // scrolling
  622. _touchPoint = this->convertTouchToNodeSpace(touch);
  623. _touchMoved = false;
  624. _dragging = true; //dragging started
  625. _scrollDistance.setZero();
  626. _touchLength = 0.0f;
  627. //zg
  628. __pageTouchBegan();
  629. }
  630. else if (_touches.size() == 2)
  631. {
  632. _touchPoint = (this->convertTouchToNodeSpace(_touches[0]).getMidpoint(
  633. this->convertTouchToNodeSpace(_touches[1])));
  634. _touchLength = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
  635. _container->convertTouchToNodeSpace(_touches[1]));
  636. _dragging = false;
  637. }
  638. return true;*/
  639. if (_isInterceptTouch){
  640. return false;
  641. }
  642. if (!this->isVisible() || !this->hasVisibleParents())
  643. {
  644. return false;
  645. }
  646. Rect frame = getViewRect();
  647. //dispatcher does not know about clipping. reject touches outside visible bounds.
  648. if (_touches.size() > 2 ||
  649. _touchMoved ||
  650. !frame.containsPoint(touch->getLocation()))
  651. {
  652. return false;
  653. }
  654. if (std::find(_touches.begin(), _touches.end(), touch) == _touches.end())
  655. {
  656. _touches.push_back(touch);
  657. }
  658. if (_touches.size() == 1)
  659. { // scrolling
  660. _touchPoint = this->convertTouchToNodeSpace(touch);
  661. _touchMoved = false;
  662. _dragging = true; //dragging started
  663. _scrollDistance.setZero();
  664. _touchLength = 0.0f;
  665. handlePressLogic(touch);
  666. //zg
  667. __pageTouchBegan();
  668. }
  669. else if (_touches.size() == 2)
  670. {
  671. _touchPoint = (this->convertTouchToNodeSpace(_touches[0]).getMidpoint(
  672. this->convertTouchToNodeSpace(_touches[1])));
  673. _touchLength = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
  674. _container->convertTouchToNodeSpace(_touches[1]));
  675. _dragging = false;
  676. }
  677. return true;
  678. }
  679. void ScrollViewSmooth::onTouchMoved(Touch* touch, Event* /*event*/)
  680. {
  681. /*
  682. if (!this->isVisible())
  683. {
  684. return;
  685. }
  686. if (std::find(_touches.begin(), _touches.end(), touch) != _touches.end())
  687. {
  688. if (_touches.size() == 1 && _dragging)
  689. { // scrolling
  690. Vec2 moveDistance, newPoint;
  691. Rect frame;
  692. float newX, newY;
  693. frame = getViewRect();
  694. newPoint = this->convertTouchToNodeSpace(_touches[0]);
  695. moveDistance = newPoint - _touchPoint;
  696. float dis = 0.0f;
  697. if (_direction == Direction::VERTICAL)
  698. {
  699. dis = moveDistance.y;
  700. float pos = _container->getPosition().y;
  701. if (!(minContainerOffset().y <= pos && pos <= maxContainerOffset().y)) {
  702. moveDistance.y *= BOUNCE_BACK_FACTOR;
  703. }
  704. }
  705. else if (_direction == Direction::HORIZONTAL)
  706. {
  707. dis = moveDistance.x;
  708. float pos = _container->getPosition().x;
  709. if (!(minContainerOffset().x <= pos && pos <= maxContainerOffset().x)) {
  710. moveDistance.x *= BOUNCE_BACK_FACTOR;
  711. }
  712. }
  713. else
  714. {
  715. dis = sqrtf(moveDistance.x*moveDistance.x + moveDistance.y*moveDistance.y);
  716. float pos = _container->getPosition().y;
  717. if (!(minContainerOffset().y <= pos && pos <= maxContainerOffset().y)) {
  718. moveDistance.y *= BOUNCE_BACK_FACTOR;
  719. }
  720. pos = _container->getPosition().x;
  721. if (!(minContainerOffset().x <= pos && pos <= maxContainerOffset().x)) {
  722. moveDistance.x *= BOUNCE_BACK_FACTOR;
  723. }
  724. }
  725. if (!_touchMoved && fabs(convertDistanceFromPointToInch(dis)) < MOVE_INCH )
  726. {
  727. //CCLOG("Invalid movement, distance = [%f, %f], disInch = %f", moveDistance.x, moveDistance.y);
  728. return;
  729. }
  730. if (!_touchMoved)
  731. {
  732. moveDistance.setZero();
  733. }
  734. _touchPoint = newPoint;
  735. _touchMoved = true;
  736. if (_dragging)
  737. {
  738. switch (_direction)
  739. {
  740. case Direction::VERTICAL:
  741. moveDistance.set(0.0f, moveDistance.y);
  742. break;
  743. case Direction::HORIZONTAL:
  744. moveDistance.set(moveDistance.x, 0.0f);
  745. break;
  746. default:
  747. break;
  748. }
  749. newX = _container->getPosition().x + moveDistance.x;
  750. newY = _container->getPosition().y + moveDistance.y;
  751. _scrollDistance = moveDistance;
  752. this->setContentOffset(Vec2(newX, newY));
  753. }
  754. }
  755. else if (_touches.size() == 2 && !_dragging)
  756. {
  757. const float len = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
  758. _container->convertTouchToNodeSpace(_touches[1]));
  759. this->setZoomScale(this->getZoomScale()*len/_touchLength);
  760. }
  761. }*/
  762. if (!this->isVisible())
  763. {
  764. return;
  765. }
  766. if (std::find(_touches.begin(), _touches.end(), touch) != _touches.end())
  767. {
  768. if (_touches.size() == 1 && _dragging)
  769. { // scrolling
  770. Vec2 moveDistance, newPoint;
  771. Rect frame;
  772. float newX, newY;
  773. frame = getViewRect();
  774. newPoint = this->convertTouchToNodeSpace(_touches[0]);
  775. moveDistance = newPoint - _touchPoint;
  776. float dis = 0.0f;
  777. if (_direction == Direction::VERTICAL)
  778. {
  779. dis = moveDistance.y;
  780. float pos = _container->getPosition().y;
  781. if (!(minContainerOffset().y <= pos && pos <= maxContainerOffset().y)) {
  782. moveDistance.y *= BOUNCE_BACK_FACTOR;
  783. }
  784. }
  785. else if (_direction == Direction::HORIZONTAL)
  786. {
  787. dis = moveDistance.x;
  788. float pos = _container->getPosition().x;
  789. if (!(minContainerOffset().x <= pos && pos <= maxContainerOffset().x)) {
  790. moveDistance.x *= BOUNCE_BACK_FACTOR;
  791. }
  792. }
  793. else
  794. {
  795. dis = sqrtf(moveDistance.x*moveDistance.x + moveDistance.y*moveDistance.y);
  796. float pos = _container->getPosition().y;
  797. if (!(minContainerOffset().y <= pos && pos <= maxContainerOffset().y)) {
  798. moveDistance.y *= BOUNCE_BACK_FACTOR;
  799. }
  800. pos = _container->getPosition().x;
  801. if (!(minContainerOffset().x <= pos && pos <= maxContainerOffset().x)) {
  802. moveDistance.x *= BOUNCE_BACK_FACTOR;
  803. }
  804. }
  805. if (!_touchMoved && fabs(convertDistanceFromPointToInch(dis)) < MOVE_INCH )
  806. {
  807. //CCLOG("Invalid movement, distance = [%f, %f], disInch = %f", moveDistance.x, moveDistance.y);
  808. return;
  809. }
  810. if (!_touchMoved)
  811. {
  812. moveDistance.setZero();
  813. }
  814. _touchPoint = newPoint;
  815. _touchMoved = true;
  816. if (_dragging)
  817. {
  818. switch (_direction)
  819. {
  820. case Direction::VERTICAL:
  821. moveDistance.set(0.0f, moveDistance.y);
  822. break;
  823. case Direction::HORIZONTAL:
  824. moveDistance.set(moveDistance.x, 0.0f);
  825. break;
  826. default:
  827. moveDistance.set(moveDistance.x, moveDistance.y);
  828. break;
  829. }
  830. newX = _container->getPosition().x + moveDistance.x;
  831. newY = _container->getPosition().y + moveDistance.y;
  832. _scrollDistance = moveDistance;
  833. handleMoveLogic(touch);
  834. // this->setContentOffset(Vec2(newX, newY));
  835. }
  836. }
  837. else if (_touches.size() == 2 && !_dragging)
  838. {
  839. const float len = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
  840. _container->convertTouchToNodeSpace(_touches[1]));
  841. this->setZoomScale(this->getZoomScale()*len/_touchLength);
  842. }
  843. }
  844. }
  845. void ScrollViewSmooth::onTouchEnded(Touch* touch, Event* /*event*/)
  846. {
  847. /*
  848. if (!this->isVisible())
  849. {
  850. return;
  851. }
  852. auto touchIter = std::find(_touches.begin(), _touches.end(), touch);
  853. if (touchIter != _touches.end())
  854. {
  855. if (_touches.size() == 1 && _touchMoved)
  856. {
  857. // this->schedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::deaccelerateScrolling));
  858. //zg
  859. if (__pageTouchEnd()) {
  860. __pageClearTouch();
  861. } else {
  862. // this->schedule(CC_SCHEDULE_SELECTOR(ScrollViewSmooth::deaccelerateScrolling));
  863. }
  864. }
  865. _touches.erase(touchIter);
  866. }
  867. if (_touches.size() == 0)
  868. {
  869. _dragging = false;
  870. _touchMoved = false;
  871. }*/
  872. if (!this->isVisible())
  873. {
  874. return;
  875. }
  876. auto touchIter = std::find(_touches.begin(), _touches.end(), touch);
  877. _touches.erase(touchIter);
  878. if (_touches.size() == 0)
  879. {
  880. _dragging = false;
  881. _touchMoved = false;
  882. }
  883. if (!_isInterceptTouch)
  884. {
  885. handleReleaseLogic(touch);
  886. }
  887. _isInterceptTouch = false;
  888. }
  889. void ScrollViewSmooth::onTouchCancelled(Touch* touch, Event* /*event*/)
  890. {/*
  891. if (!this->isVisible())
  892. {
  893. return;
  894. }
  895. auto touchIter = std::find(_touches.begin(), _touches.end(), touch);
  896. _touches.erase(touchIter);
  897. if (_touches.size() == 0)
  898. {
  899. _dragging = false;
  900. _touchMoved = false;
  901. }*/
  902. if (!this->isVisible())
  903. {
  904. return;
  905. }
  906. auto touchIter = std::find(_touches.begin(), _touches.end(), touch);
  907. _touches.erase(touchIter);
  908. if (_touches.size() == 0)
  909. {
  910. _dragging = false;
  911. _touchMoved = false;
  912. }
  913. if (!_isInterceptTouch)
  914. {
  915. handleReleaseLogic(touch);
  916. }
  917. _isInterceptTouch = false;
  918. }
  919. Rect ScrollViewSmooth::getViewRect()
  920. {
  921. Vec2 screenPos = this->convertToWorldSpace(Vec2::ZERO);
  922. float scaleX = this->getScaleX();
  923. float scaleY = this->getScaleY();
  924. for (Node *p = _parent; p != nullptr; p = p->getParent()) {
  925. scaleX *= p->getScaleX();
  926. scaleY *= p->getScaleY();
  927. }
  928. // Support negative scaling. Not doing so causes intersectsRect calls
  929. // (eg: to check if the touch was within the bounds) to return false.
  930. // Note, Node::getScale will assert if X and Y scales are different.
  931. if(scaleX<0.f) {
  932. screenPos.x += _viewSize.width*scaleX;
  933. scaleX = -scaleX;
  934. }
  935. if(scaleY<0.f) {
  936. screenPos.y += _viewSize.height*scaleY;
  937. scaleY = -scaleY;
  938. }
  939. return Rect(screenPos.x, screenPos.y, _viewSize.width*scaleX, _viewSize.height*scaleY);
  940. }
  941. // zg
  942. void ScrollViewSmooth::__pageTouchBegan()
  943. {
  944. //仅在设置了分页属性, 并且只有一个滑动方向的时候, 才支持分页.
  945. if( !m_bPaged || ( _direction != Direction::HORIZONTAL && _direction != Direction::VERTICAL )) return ;
  946. //记录初试时间和位置
  947. m_touchBeganTime = clock();
  948. m_touchBeganOffset = _direction == Direction::HORIZONTAL ? getContentOffset().x : getContentOffset().y;
  949. }
  950. bool ScrollViewSmooth::__pageTouchEnd()
  951. {
  952. if( !m_bPaged || ( _direction != Direction::HORIZONTAL && _direction != Direction::VERTICAL)) return false ;
  953. //constant
  954. const float PAGE_DISTENCE = _direction == Direction::HORIZONTAL ? getViewSize().width + m_pageAdjustSize.width: getViewSize().height + m_pageAdjustSize.height;
  955. if( PAGE_DISTENCE <= 0 ) return false;
  956. const float MAX_PAGE = ( _direction == Direction::HORIZONTAL ? getContentSize().width : getContentSize().height ) / PAGE_DISTENCE - 1;
  957. const float MIN_PAGE = 0;
  958. float currOffset = _direction == Direction::HORIZONTAL ? getContentOffset().x : getContentOffset().y;
  959. float deltaOffset = -(currOffset - m_touchBeganOffset);
  960. clock_t currTime = clock();
  961. float speed = currTime != m_touchBeganTime ? deltaOffset / ( currTime - m_touchBeganTime ) : 0;
  962. m_targetPage = m_currPage;
  963. if( std::abs(deltaOffset) >= TURN_PAGE_MIN_OFFSET_RATIO * PAGE_DISTENCE )
  964. {//滑动距离大于某一阈值.
  965. if( deltaOffset > 0 )
  966. {
  967. m_targetPage = m_currPage + 1;
  968. }
  969. else if( deltaOffset < 0 )
  970. {
  971. m_targetPage = m_currPage - 1;
  972. }
  973. }
  974. else if( std::abs(speed) >= TURN_PAGE_SPEED )
  975. {//速度大于某一阈值.
  976. if( speed > 0 )
  977. {
  978. m_targetPage = m_currPage + 1;
  979. }
  980. else if( speed < 0 )
  981. {
  982. m_targetPage = m_currPage - 1;
  983. }
  984. }
  985. if( m_targetPage > MAX_PAGE ) {
  986. m_targetPage = MAX_PAGE;
  987. }
  988. else if( m_targetPage < MIN_PAGE ) {
  989. m_targetPage = MIN_PAGE;
  990. }
  991. float targetOffset = -m_targetPage * ( _direction == Direction::HORIZONTAL ? getViewSize().width + m_pageAdjustSize.width: getViewSize().height + m_pageAdjustSize.height);
  992. if (m_targetPage == MAX_PAGE) {
  993. targetOffset -= (_direction == Direction::HORIZONTAL ? m_pageAdjustSize.width : m_pageAdjustSize.height);
  994. }
  995. float pageDurateion = 0.2;
  996. Point targetPointOffset = _direction == Direction::HORIZONTAL ? Point( targetOffset, getContentOffset().y ) : Point(getContentOffset().x, targetOffset );
  997. setContentOffsetInDuration(targetPointOffset, pageDurateion);
  998. if(_callFunc && (m_currPage != m_targetPage)){
  999. (this->*_callFunc)(m_targetPage);
  1000. }
  1001. m_currPage = m_targetPage;
  1002. return true;
  1003. }
  1004. void ScrollViewSmooth::__pageTouchCancel()
  1005. {
  1006. if( !m_bPaged || ( _direction != Direction::HORIZONTAL && _direction != Direction::VERTICAL )) return ;
  1007. __pageClearTouch();
  1008. }
  1009. void ScrollViewSmooth::__pageClearTouch()
  1010. {
  1011. //clear所有状态
  1012. m_touchBeganOffset = 0;
  1013. m_touchBeganTime = 0;
  1014. m_targetPage = m_currPage;
  1015. }
  1016. void ScrollViewSmooth::zgMoveToPage(int page) {
  1017. if (page != m_currPage) {
  1018. float targetOffset = -page * (_direction == Direction::HORIZONTAL ? getViewSize().width : getViewSize().height);
  1019. Point targetPointOffset = _direction == Direction::HORIZONTAL ? Point( targetOffset, getContentOffset().y ) : Point(getContentOffset().x, targetOffset );
  1020. setContentOffset(targetPointOffset);
  1021. m_currPage = page;
  1022. if(_callFunc){
  1023. (this->*_callFunc)(m_currPage);
  1024. }
  1025. }
  1026. }
  1027. void ScrollViewSmooth::zgMoveToPageWithAnimation(int page) {
  1028. if (page != m_currPage) {
  1029. float targetOffset = -page * (_direction == Direction::HORIZONTAL ? getViewSize().width : getViewSize().height);
  1030. float pageDurateion = 0.2;
  1031. Point targetPointOffset = _direction == Direction::HORIZONTAL ? Point( targetOffset, getContentOffset().y ) : Point(getContentOffset().x, targetOffset );
  1032. setContentOffsetInDuration(targetPointOffset, pageDurateion);
  1033. m_currPage = page;
  1034. if(_callFunc){
  1035. (this->*_callFunc)(m_currPage);
  1036. }
  1037. }
  1038. }
  1039. #pragma mask UItouch
  1040. void ScrollViewSmooth::handlePressLogic(Touch *touch){
  1041. _bePressed = true;
  1042. _autoScrolling = false;
  1043. // Clear gathered touch move information
  1044. {
  1045. _touchMovePreviousTimestamp = utils::getTimeInMilliseconds();
  1046. _touchMoveDisplacements.clear();
  1047. _touchMoveTimeDeltas.clear();
  1048. }
  1049. }
  1050. void ScrollViewSmooth::handleMoveLogic(Touch *touch){
  1051. Vec2 currPt, prevPt;
  1052. // if(!calculateCurrAndPrevTouchPoints(touch, &currPt, &prevPt))
  1053. // {
  1054. // return;
  1055. // }
  1056. currPt = convertTouchToNodeSpace(touch);
  1057. prevPt = convertToNodeSpace(touch->getPreviousLocation());
  1058. Vec2 delta = currPt - prevPt;
  1059. // Vec2 delta(delta3.x, delta3.y);
  1060. scrollChildren(delta);
  1061. // Gather touch move information for speed calculation
  1062. // 收集触摸移动信息以进行速度计算
  1063. gatherTouchMove(delta);
  1064. }
  1065. void ScrollViewSmooth::handleReleaseLogic(Touch *touch){
  1066. // Gather the last touch information when released
  1067. {
  1068. Vec2 currPt, prevPt;
  1069. currPt = convertTouchToNodeSpace(touch);
  1070. prevPt = convertToNodeSpace(touch->getPreviousLocation());
  1071. Vec2 delta = currPt - prevPt;
  1072. gatherTouchMove(delta);
  1073. }
  1074. _bePressed = false;
  1075. bool bounceBackStarted = startBounceBackIfNeeded();
  1076. // bool bounceBackStarted = false;
  1077. // if(!bounceBackStarted && _inertiaScrollEnabled)
  1078. if(!bounceBackStarted)
  1079. {
  1080. Vec2 touchMoveVelocity = calculateTouchMoveVelocity();
  1081. if(touchMoveVelocity != Vec2::ZERO)
  1082. {
  1083. startInertiaScroll(touchMoveVelocity);
  1084. }
  1085. }
  1086. }
  1087. void ScrollViewSmooth::scrollChildren(const Vec2& deltaMove)
  1088. {
  1089. Vec2 realMove = deltaMove;
  1090. if(_bounceable)
  1091. {
  1092. // If the position of the inner container is out of the boundary, the offsets should be divided by two.
  1093. Vec2 outOfBoundary = getHowMuchOutOfBoundary();
  1094. // log("outOfBoundaryX %f, outOfBoundaryY %f",outOfBoundary.x,outOfBoundary.y);//手没离开的时候计算滑动用的log
  1095. realMove.x *= (outOfBoundary.x == 0 ? 1 : 0.5f);
  1096. realMove.y *= (outOfBoundary.y == 0 ? 1 : 0.5f);
  1097. }
  1098. if(!_bounceable)
  1099. {
  1100. Vec2 outOfBoundary = getHowMuchOutOfBoundary(realMove);
  1101. realMove += outOfBoundary;
  1102. }
  1103. // bool scrolledToLeft = false;
  1104. // bool scrolledToRight = false;
  1105. // bool scrolledToTop = false;
  1106. // bool scrolledToBottom = false;
  1107. // if (realMove.y > 0.0f) // up
  1108. // {
  1109. // float icBottomPos = _container->getBottomBoundary();
  1110. // if (icBottomPos + realMove.y >= 0)
  1111. // {
  1112. // scrolledToBottom = true;
  1113. // }
  1114. // }
  1115. // else if (realMove.y < 0.0f) // down
  1116. // {
  1117. // float icTopPos = _innerContainer->getTopBoundary();
  1118. // if (icTopPos + realMove.y <= _topBoundary)
  1119. // {
  1120. // scrolledToTop = true;
  1121. // }
  1122. // }
  1123. //
  1124. // if (realMove.x < 0.0f) // left
  1125. // {
  1126. // float icRightPos = _innerContainer->getRightBoundary();
  1127. // if (icRightPos + realMove.x <= _rightBoundary)
  1128. // {
  1129. // scrolledToRight = true;
  1130. // }
  1131. // }
  1132. // else if (realMove.x > 0.0f) // right
  1133. // {
  1134. // float icLeftPos = _innerContainer->getLeftBoundary();
  1135. // if (icLeftPos + realMove.x >= _leftBoundary)
  1136. // {
  1137. // scrolledToLeft = true;
  1138. // }
  1139. // }
  1140. moveInnerContainer(realMove, false);
  1141. }
  1142. Vec2 ScrollViewSmooth::getHowMuchOutOfBoundary(const Vec2& addition)
  1143. {
  1144. // if(addition == Vec2::ZERO && !_outOfBoundaryAmountDirty)
  1145. // {
  1146. // return _outOfBoundaryAmount;
  1147. // }
  1148. // Vec2 outOfBoundaryAmount(Vec2::ZERO);
  1149. // if(_innerContainer->getLeftBoundary() + addition.x > _leftBoundary)
  1150. // {
  1151. // outOfBoundaryAmount.x = _leftBoundary - (_innerContainer->getLeftBoundary() + addition.x);
  1152. // }
  1153. // else if(_innerContainer->getRightBoundary() + addition.x < _rightBoundary)
  1154. // {
  1155. // outOfBoundaryAmount.x = _rightBoundary - (_innerContainer->getRightBoundary() + addition.x);
  1156. // }
  1157. //
  1158. // if(_innerContainer->getTopBoundary() + addition.y < _topBoundary)
  1159. // {
  1160. // outOfBoundaryAmount.y = _topBoundary - (_innerContainer->getTopBoundary() + addition.y);
  1161. // }
  1162. // else if(_innerContainer->getBottomBoundary() + addition.y > _bottomBoundary)
  1163. // {
  1164. // outOfBoundaryAmount.y = _bottomBoundary - (_innerContainer->getBottomBoundary() + addition.y);
  1165. // }
  1166. //
  1167. // if(addition == Vec2::ZERO)
  1168. // {
  1169. // _outOfBoundaryAmount = outOfBoundaryAmount;
  1170. // _outOfBoundaryAmountDirty = false;
  1171. // }
  1172. // return outOfBoundaryAmount;
  1173. Vec2 outOfBoundaryAmount(Vec2::ZERO);
  1174. const Vec2 minOffset = this->minContainerOffset();
  1175. const Vec2 maxOffset = this->maxContainerOffset();
  1176. if (_container->getPosition().y + addition.y < minOffset.y) {
  1177. outOfBoundaryAmount.y = minOffset.y - (_container->getPosition().y + addition.y);
  1178. }
  1179. return outOfBoundaryAmount;
  1180. }
  1181. void ScrollViewSmooth::moveInnerContainer(const Vec2& deltaMove, bool canStartBounceBack)
  1182. {
  1183. Vec2 adjustedMove = flattenVectorByDirection(deltaMove);
  1184. // log("moveInnerContainerX %f,moveInnerContainerY %f ,canStartBounceBack is %d",deltaMove.x,deltaMove.y,canStartBounceBack);
  1185. // setInnerContainerPosition(getInnerContainerPosition() + adjustedMove);
  1186. setContentOffset(getContentOffset() + adjustedMove);
  1187. if(_bounceable && canStartBounceBack)
  1188. {
  1189. startBounceBackIfNeeded();
  1190. }
  1191. }
  1192. Vec2 ScrollViewSmooth::flattenVectorByDirection(const Vec2& vector)
  1193. {
  1194. Vec2 result = vector;
  1195. // result.x = (_direction == Direction::VERTICAL || _direction == Direction::BOTH ? 0 : result.x);
  1196. // result.y = (_direction == Direction::HORIZONTAL || _direction == Direction::BOTH ? 0 : result.y);
  1197. result.x = (_direction == Direction::VERTICAL ? 0 : result.x);
  1198. result.y = (_direction == Direction::HORIZONTAL ? 0 : result.y);
  1199. return result;
  1200. }
  1201. void ScrollViewSmooth::gatherTouchMove(const Vec2& delta)
  1202. {
  1203. while(_touchMoveDisplacements.size() >= 5)
  1204. {
  1205. _touchMoveDisplacements.pop_front();
  1206. _touchMoveTimeDeltas.pop_front();
  1207. }
  1208. _touchMoveDisplacements.push_back(delta);
  1209. long long timestamp = utils::getTimeInMilliseconds();
  1210. _touchMoveTimeDeltas.push_back((timestamp - _touchMovePreviousTimestamp) / 1000.0f);
  1211. _touchMovePreviousTimestamp = timestamp;
  1212. }
  1213. Vec2 ScrollViewSmooth::calculateTouchMoveVelocity() const
  1214. {
  1215. float totalTime = 0;
  1216. // log("------------------------------------------");
  1217. for(auto &timeDelta : _touchMoveTimeDeltas)
  1218. {
  1219. // log("------- timeDelta %f", timeDelta);
  1220. totalTime += timeDelta;
  1221. }
  1222. // log("------- totalTime %f", totalTime);
  1223. if(totalTime == 0/* || totalTime >= 0.5*/)
  1224. {
  1225. // log("------- totalTime changed is not good");
  1226. return Vec2::ZERO;
  1227. }
  1228. if (totalTime < 0.01) {
  1229. // log("------- totalTime changed1 ---------- %f", totalTime);
  1230. totalTime = 0.2;
  1231. } else if (totalTime < 0.02 && totalTime >= 0.01) {
  1232. // log("------- totalTime changed2 ---------- %f", totalTime);
  1233. totalTime = 0.02;
  1234. } else if (totalTime >= 0.5) {
  1235. // log("------- totalTime changed3 ---------- %f", totalTime);
  1236. totalTime = 0.5;
  1237. }
  1238. // log("------------------------------------------");
  1239. Vec2 totalMovement;
  1240. for(auto &displacement : _touchMoveDisplacements)
  1241. {
  1242. totalMovement += displacement;
  1243. }
  1244. return totalMovement / totalTime;
  1245. }
  1246. void ScrollViewSmooth::startInertiaScroll(const Vec2& touchMoveVelocity)
  1247. {
  1248. const float MOVEMENT_FACTOR = 0.7f;
  1249. Vec2 inertiaTotalMovement = touchMoveVelocity * MOVEMENT_FACTOR;
  1250. startAttenuatingAutoScroll(inertiaTotalMovement, touchMoveVelocity);
  1251. }
  1252. void ScrollViewSmooth::startAttenuatingAutoScroll(const Vec2& deltaMove, const Vec2& initialVelocity)
  1253. {
  1254. float time = calculateAutoScrollTimeByInitialSpeed(initialVelocity.length());
  1255. startAutoScroll(deltaMove, time, true);
  1256. }
  1257. bool ScrollViewSmooth::isNecessaryAutoScrollBrake()
  1258. {
  1259. if(_autoScrollBraking)
  1260. {
  1261. return true;
  1262. }
  1263. Vec2 bounceBackAmount = getHowMuchOutOfBoundary();
  1264. if(!fltEqualZero(bounceBackAmount))
  1265. {
  1266. // It just went out of boundary.
  1267. if(!_autoScrollCurrentlyOutOfBoundary)
  1268. {
  1269. _autoScrollCurrentlyOutOfBoundary = true;
  1270. _autoScrollBraking = true;
  1271. _autoScrollBrakingStartPosition = _container->getPosition();
  1272. return true;
  1273. }
  1274. }
  1275. else
  1276. {
  1277. _autoScrollCurrentlyOutOfBoundary = false;
  1278. }
  1279. return false;
  1280. }
  1281. bool ScrollViewSmooth::startBounceBackIfNeeded()
  1282. {
  1283. if (!_bounceable)
  1284. {
  1285. return false;
  1286. }
  1287. Vec2 bounceBackAmount = getHowMuchOutOfBoundary();
  1288. if(fltEqualZero(bounceBackAmount))
  1289. {
  1290. return false;
  1291. }
  1292. startAutoScroll(bounceBackAmount, 1.0f, true);
  1293. return true;
  1294. }
  1295. float ScrollViewSmooth::calculateAutoScrollTimeByInitialSpeed(float initialSpeed)
  1296. {
  1297. // Calculate the time from the initial speed according to quintic polynomial.
  1298. float time = sqrtf(sqrtf(initialSpeed / 5));
  1299. return time;
  1300. }
  1301. void ScrollViewSmooth::startAutoScroll(const Vec2& deltaMove, float timeInSec, bool attenuated)
  1302. {
  1303. Vec2 adjustedDeltaMove = flattenVectorByDirection(deltaMove);// 单方向
  1304. _autoScrolling = true;
  1305. _autoScrollTargetDelta = adjustedDeltaMove;
  1306. // _autoScrollAttenuate = attenuated;
  1307. _autoScrollStartPosition = getContentOffset();
  1308. _autoScrollTotalTime = timeInSec;
  1309. _autoScrollAccumulatedTime = 0;
  1310. _autoScrollBraking = false;
  1311. _autoScrollBrakingStartPosition = Vec2::ZERO;
  1312. // If the destination is also out of boundary of same side, start brake from beginning.
  1313. Vec2 currentOutOfBoundary = getHowMuchOutOfBoundary();
  1314. if (!fltEqualZero(currentOutOfBoundary))
  1315. {
  1316. _autoScrollCurrentlyOutOfBoundary = true;
  1317. Vec2 afterOutOfBoundary = getHowMuchOutOfBoundary(adjustedDeltaMove);
  1318. if(currentOutOfBoundary.x * afterOutOfBoundary.x > 0 || currentOutOfBoundary.y * afterOutOfBoundary.y > 0)
  1319. {
  1320. _autoScrollBraking = true;
  1321. }
  1322. }
  1323. }
  1324. #pragma mask update
  1325. void ScrollViewSmooth::update(float dt)
  1326. {
  1327. if (_autoScrolling)
  1328. {
  1329. processAutoScrolling(dt);
  1330. }
  1331. }
  1332. //手离开的时候计算滑动用的log
  1333. void ScrollViewSmooth::processAutoScrolling(float deltaTime)
  1334. {
  1335. // Make auto scroll shorter if it needs to deaccelerate.
  1336. //如果需要减速,请使自动滚动更短。
  1337. // float brakingFactor = (/* DISABLES CODE */ (false) ? 0.05 : 1);
  1338. float brakingFactor = (isNecessaryAutoScrollBrake() ? 0.05 : 1);
  1339. // log("brakingFactor is %f",brakingFactor);
  1340. // Elapsed time
  1341. _autoScrollAccumulatedTime += deltaTime * (1 / brakingFactor);
  1342. // Calculate the progress percentage
  1343. float percentage = MIN(1, _autoScrollAccumulatedTime / _autoScrollTotalTime);
  1344. bool _autoScrollAttenuate = true;
  1345. if(_autoScrollAttenuate)
  1346. {
  1347. // Use quintic(5th degree) polynomial
  1348. percentage = tweenfunc::quintEaseOut(percentage);
  1349. }
  1350. // Calculate the new position
  1351. Vec2 newPosition = _autoScrollStartPosition + (_autoScrollTargetDelta * percentage);
  1352. bool reachedEnd = std::abs(percentage - 1) <= FLT_EPSILON;
  1353. if (reachedEnd)
  1354. {
  1355. newPosition = _autoScrollStartPosition + _autoScrollTargetDelta;
  1356. }
  1357. if(_bounceable)
  1358. {
  1359. // The new position is adjusted if out of boundary
  1360. newPosition = _autoScrollBrakingStartPosition + (newPosition - _autoScrollBrakingStartPosition) * brakingFactor;
  1361. }
  1362. else
  1363. {
  1364. // Don't let go out of boundary
  1365. // Vec2 moveDelta = newPosition - getContentOffset();
  1366. // Vec2 outOfBoundary = getHowMuchOutOfBoundary(moveDelta);
  1367. // if (!fltEqualZero(outOfBoundary))
  1368. // {
  1369. // newPosition += outOfBoundary;
  1370. // reachedEnd = true;
  1371. // }
  1372. }
  1373. // Finish auto scroll if it ended
  1374. if(reachedEnd)
  1375. {
  1376. _autoScrolling = false;
  1377. // dispatchEvent(SCROLLVIEW_EVENT_AUTOSCROLL_ENDED, EventType::AUTOSCROLL_ENDED);
  1378. }
  1379. moveInnerContainer(newPosition - getContentOffset(), reachedEnd);
  1380. }
  1381. bool ScrollViewSmooth::fltEqualZero(const Vec2& point) const
  1382. {
  1383. return (fabsf(point.x) <= 0.0001f && fabsf(point.y) <= 0.0001f);
  1384. }
  1385. void ScrollViewSmooth::onEnter(){
  1386. Layer::onEnter();
  1387. scheduleUpdate();
  1388. }
  1389. NS_CC_EXT_END