From 96a78f687cfa1e8d5bffc85a4d394bd1f149f55e Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Sun, 19 Jul 2015 11:41:20 +0900 Subject: [PATCH 1/7] Remove redundant codes --- cocos/ui/UIScrollView.cpp | 71 ++++++++++++++++++--------------------- cocos/ui/UIScrollView.h | 4 --- 2 files changed, 32 insertions(+), 43 deletions(-) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index 2c23915930..c4f976b689 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -31,8 +31,6 @@ THE SOFTWARE. #include "2d/CCCamera.h" NS_CC_BEGIN -namespace ui { - static const float INERTIA_DEACCELERATION = 700.0f; static const float INERTIA_VELOCITY_MAX = 2500; static const float BOUNCE_BACK_DURATION = 1.0f; @@ -46,6 +44,8 @@ static float convertDistanceFromPointToInch(const Vec2& dis) return distance; } +namespace ui { + IMPLEMENT_CLASS_GUI_INFO(ScrollView) ScrollView::ScrollView(): @@ -482,11 +482,6 @@ void ScrollView::startInertiaScroll() { totalMovement += displacement; } - - for(auto i = _inertiaTouchDisplacements.begin(); i != _inertiaTouchDisplacements.end(); ++i) - { - totalMovement += (*i); - } totalMovement.x = (_direction == Direction::VERTICAL ? 0 : totalMovement.x); totalMovement.y = (_direction == Direction::HORIZONTAL ? 0 : totalMovement.y); @@ -803,36 +798,26 @@ void ScrollView::jumpToPercentBothDirection(const Vec2& percent) jumpToDestination(Vec2(-(percent.x * w / 100.0f), minY + percent.y * h / 100.0f)); } -void ScrollView::startRecordSlidAction() +void ScrollView::handlePressLogic(Touch *touch) { - if (_inertiaScrolling) + _bePressed = true; + + if(_inertiaScrollEnabled) { - _inertiaScrolling = false; + if (_inertiaScrolling) + { + _inertiaScrolling = false; + } + _inertiaPrevTouchTimestamp = utils::getTimeInMilliseconds(); + _inertiaTouchDisplacements.clear(); + _inertiaTouchTimeDeltas.clear(); } + if(_autoScrolling) { _autoScrolling = false; _bouncingBack = false; } -} - -void ScrollView::endRecordSlidAction() -{ - bool bounceBackStarted = startBounceBackIfNeeded(); - if(!bounceBackStarted && _inertiaScrollEnabled) - { - startInertiaScroll(); - } -} - -void ScrollView::handlePressLogic(Touch *touch) -{ - startRecordSlidAction(); - _bePressed = true; - - _inertiaPrevTouchTimestamp = utils::getTimeInMilliseconds(); - _inertiaTouchDisplacements.clear(); - _inertiaTouchTimeDeltas.clear(); if(_verticalScrollBar != nullptr) { @@ -856,24 +841,32 @@ void ScrollView::handleMoveLogic(Touch *touch) Vec3 delta3 = currPt - prevPt; Vec2 delta(delta3.x, delta3.y); scrollChildren(delta.x, delta.y); - - while(_inertiaTouchDisplacements.size() > 5) + + if(_inertiaScrollEnabled) { - _inertiaTouchDisplacements.pop_front(); - _inertiaTouchTimeDeltas.pop_front(); + while(_inertiaTouchDisplacements.size() > 5) + { + _inertiaTouchDisplacements.pop_front(); + _inertiaTouchTimeDeltas.pop_front(); + } + _inertiaTouchDisplacements.push_back(delta); + + long long timestamp = utils::getTimeInMilliseconds(); + _inertiaTouchTimeDeltas.push_back((timestamp - _inertiaPrevTouchTimestamp) / 1000.0f); + _inertiaPrevTouchTimestamp = timestamp; } - _inertiaTouchDisplacements.push_back(delta); - - long long timestamp = utils::getTimeInMilliseconds(); - _inertiaTouchTimeDeltas.push_back((timestamp - _inertiaPrevTouchTimestamp) / 1000.0f); - _inertiaPrevTouchTimestamp = timestamp; } void ScrollView::handleReleaseLogic(Touch *touch) { - endRecordSlidAction(); _bePressed = false; + bool bounceBackStarted = startBounceBackIfNeeded(); + if(!bounceBackStarted && _inertiaScrollEnabled) + { + startInertiaScroll(); + } + if(_verticalScrollBar != nullptr) { _verticalScrollBar->onTouchEnded(); diff --git a/cocos/ui/UIScrollView.h b/cocos/ui/UIScrollView.h index 8f311ee458..6414c98d37 100644 --- a/cocos/ui/UIScrollView.h +++ b/cocos/ui/UIScrollView.h @@ -585,10 +585,6 @@ protected: virtual bool scrollChildren(float touchOffsetX, float touchOffsetY); - void startRecordSlidAction(); - virtual void endRecordSlidAction(); - - //ScrollViewProtocol virtual void handlePressLogic(Touch *touch); virtual void handleMoveLogic(Touch *touch); virtual void handleReleaseLogic(Touch *touch); From 81795f6d73fef2b1ce9c5fe509e9adf66adc18a6 Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Fri, 7 Aug 2015 18:47:46 +0900 Subject: [PATCH 2/7] Add a guard statement in setInnerContainerPosition(). --- cocos/ui/UIScrollView.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index c4f976b689..8a2a8a9f12 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -223,6 +223,10 @@ const Size& ScrollView::getInnerContainerSize() const void ScrollView::setInnerContainerPosition(const Vec2 &position) { + if(position == _innerContainer->getPosition()) + { + return; + } _innerContainer->setPosition(position); this->retain(); From 69d23eb00cd222565a67da511d0597431a0db569 Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Sun, 30 Aug 2015 15:58:20 +0900 Subject: [PATCH 3/7] Extract the touch move speed calculation logic from inertia concept. --- cocos/ui/UIScrollView.cpp | 71 +++++++++++++++++++++++---------------- cocos/ui/UIScrollView.h | 15 ++++++--- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index 8a2a8a9f12..98192022be 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -59,7 +59,7 @@ _bePressed(false), _childFocusCancelOffsetInInch(MOVE_INCH), _inertiaScrollEnabled(true), _inertiaScrolling(false), -_inertiaPrevTouchTimestamp(0), +_touchMovePreviousTimestamp(0), _inertiaScrollExpectedTime(0), _inertiaScrollElapsedTime(0), _autoScrolling(false), @@ -466,30 +466,35 @@ void ScrollView::jumpToDestination(const Vec2 &des) moveChildrenToPosition(Vec2(finalOffsetX, finalOffsetY)); } -void ScrollView::startInertiaScroll() +Vec2 ScrollView::calculateTouchMoveSpeed() const { float totalDuration = 0; - for(auto &timeDelta : _inertiaTouchTimeDeltas) - { - totalDuration += timeDelta; - } + for(auto &timeDelta : _touchMoveTimeDeltas) + { + totalDuration += timeDelta; + } if(totalDuration == 0 || totalDuration >= 0.5f) { - return; + return Vec2::ZERO; } + Vec2 totalMovement; + for(auto &displacement : _touchMoveDisplacements) + { + totalMovement += displacement; + } + return totalMovement / totalDuration; +} + +void ScrollView::startInertiaScroll(const Vec2& touchMoveSpeed) +{ _inertiaScrolling = true; // Calcualte the initial velocity - Vec2 totalMovement; - for(auto &displacement : _inertiaTouchDisplacements) - { - totalMovement += displacement; - } - totalMovement.x = (_direction == Direction::VERTICAL ? 0 : totalMovement.x); - totalMovement.y = (_direction == Direction::HORIZONTAL ? 0 : totalMovement.y); + _inertiaInitiVelocity = touchMoveSpeed; + _inertiaInitiVelocity.x = (_direction == Direction::VERTICAL ? 0 : _inertiaInitiVelocity.x); + _inertiaInitiVelocity.y = (_direction == Direction::HORIZONTAL ? 0 : _inertiaInitiVelocity.y); - _inertiaInitiVelocity = totalMovement / totalDuration; _inertiaInitiVelocity.x = MIN(_inertiaInitiVelocity.x, INERTIA_VELOCITY_MAX); _inertiaInitiVelocity.y = MIN(_inertiaInitiVelocity.y, INERTIA_VELOCITY_MAX); _inertiaInitiVelocity.x = MAX(_inertiaInitiVelocity.x, -INERTIA_VELOCITY_MAX); @@ -806,15 +811,19 @@ void ScrollView::handlePressLogic(Touch *touch) { _bePressed = true; + // Initialize touch move information + { + _touchMovePreviousTimestamp = utils::getTimeInMilliseconds(); + _touchMoveDisplacements.clear(); + _touchMoveTimeDeltas.clear(); + } + if(_inertiaScrollEnabled) { if (_inertiaScrolling) { _inertiaScrolling = false; } - _inertiaPrevTouchTimestamp = utils::getTimeInMilliseconds(); - _inertiaTouchDisplacements.clear(); - _inertiaTouchTimeDeltas.clear(); } if(_autoScrolling) @@ -846,18 +855,18 @@ void ScrollView::handleMoveLogic(Touch *touch) Vec2 delta(delta3.x, delta3.y); scrollChildren(delta.x, delta.y); - if(_inertiaScrollEnabled) + // Gather touch move information for speed calculation { - while(_inertiaTouchDisplacements.size() > 5) + while(_touchMoveDisplacements.size() > 5) { - _inertiaTouchDisplacements.pop_front(); - _inertiaTouchTimeDeltas.pop_front(); + _touchMoveDisplacements.pop_front(); + _touchMoveTimeDeltas.pop_front(); } - _inertiaTouchDisplacements.push_back(delta); + _touchMoveDisplacements.push_back(delta); long long timestamp = utils::getTimeInMilliseconds(); - _inertiaTouchTimeDeltas.push_back((timestamp - _inertiaPrevTouchTimestamp) / 1000.0f); - _inertiaPrevTouchTimestamp = timestamp; + _touchMoveTimeDeltas.push_back((timestamp - _touchMovePreviousTimestamp) / 1000.0f); + _touchMovePreviousTimestamp = timestamp; } } @@ -868,7 +877,11 @@ void ScrollView::handleReleaseLogic(Touch *touch) bool bounceBackStarted = startBounceBackIfNeeded(); if(!bounceBackStarted && _inertiaScrollEnabled) { - startInertiaScroll(); + Vec2 touchMoveSpeed = calculateTouchMoveSpeed(); + if(touchMoveSpeed != Vec2::ZERO) + { + startInertiaScroll(touchMoveSpeed); + } } if(_verticalScrollBar != nullptr) @@ -1351,9 +1364,9 @@ void ScrollView::copySpecialProperties(Widget *widget) setInertiaScrollEnabled(scrollView->_inertiaScrollEnabled); _inertiaScrolling = scrollView->_inertiaScrolling; _inertiaInitiVelocity = scrollView->_inertiaInitiVelocity; - _inertiaTouchDisplacements = scrollView->_inertiaTouchDisplacements; - _inertiaTouchTimeDeltas = scrollView->_inertiaTouchTimeDeltas; - _inertiaPrevTouchTimestamp = scrollView->_inertiaPrevTouchTimestamp; + _touchMoveDisplacements = scrollView->_touchMoveDisplacements; + _touchMoveTimeDeltas = scrollView->_touchMoveTimeDeltas; + _touchMovePreviousTimestamp = scrollView->_touchMovePreviousTimestamp; _inertiaScrollExpectedTime = scrollView->_inertiaScrollExpectedTime; _inertiaScrollElapsedTime = scrollView->_inertiaScrollElapsedTime; _autoScrolling = scrollView->_autoScrolling; diff --git a/cocos/ui/UIScrollView.h b/cocos/ui/UIScrollView.h index 6414c98d37..598087e33e 100644 --- a/cocos/ui/UIScrollView.h +++ b/cocos/ui/UIScrollView.h @@ -572,7 +572,9 @@ protected: void moveChildren(float offsetX, float offsetY); void moveChildrenToPosition(const Vec2& position); - void startInertiaScroll(); + Vec2 calculateTouchMoveSpeed() const; + + void startInertiaScroll(const Vec2& touchMoveSpeed); void processInertiaScrolling(float dt); void startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated); @@ -612,13 +614,16 @@ protected: bool _bePressed; float _childFocusCancelOffsetInInch; - + + // Touch move speed + std::list _touchMoveDisplacements; + std::list _touchMoveTimeDeltas; + long long _touchMovePreviousTimestamp; + + // Inertia scroll bool _inertiaScrollEnabled; bool _inertiaScrolling; Vec2 _inertiaInitiVelocity; - std::list _inertiaTouchDisplacements; - std::list _inertiaTouchTimeDeltas; - long long _inertiaPrevTouchTimestamp; float _inertiaScrollExpectedTime; float _inertiaScrollElapsedTime; From 137a05a2aaf0639d8a11c6d037be3c3ccbfd1c34 Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Mon, 31 Aug 2015 12:24:33 +0900 Subject: [PATCH 4/7] Rectify the wrong indentations in switch statements --- cocos/ui/UIScrollView.cpp | 55 ++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index 98192022be..95bdcb5b4c 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -419,11 +419,12 @@ bool ScrollView::isOutOfBoundary(MoveDirection dir) const { switch(dir) { - case MoveDirection::TOP: return _innerContainer->getTopBoundary() < _topBoundary; - case MoveDirection::BOTTOM: return _innerContainer->getBottomBoundary() > _bottomBoundary; - case MoveDirection::LEFT: return _innerContainer->getLeftBoundary() > _leftBoundary; - case MoveDirection::RIGHT: return _innerContainer->getRightBoundary() < _rightBoundary; + case MoveDirection::TOP: return _innerContainer->getTopBoundary() < _topBoundary; + case MoveDirection::BOTTOM: return _innerContainer->getBottomBoundary() > _bottomBoundary; + case MoveDirection::LEFT: return _innerContainer->getLeftBoundary() > _leftBoundary; + case MoveDirection::RIGHT: return _innerContainer->getRightBoundary() < _rightBoundary; } + return false; } bool ScrollView::isOutOfBoundaryTopOrBottom() const @@ -1012,29 +1013,29 @@ void ScrollView::processScrollEvent(MoveDirection dir, bool bounce) ScrollviewEventType scrollEventType; EventType eventType; switch(dir) { - case MoveDirection::TOP: - { - scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_TOP : SCROLLVIEW_EVENT_SCROLL_TO_TOP); - eventType = (bounce ? EventType::BOUNCE_TOP : EventType::SCROLL_TO_TOP); - break; - } - case MoveDirection::BOTTOM: - { - scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_BOTTOM : SCROLLVIEW_EVENT_SCROLL_TO_BOTTOM); - eventType = (bounce ? EventType::BOUNCE_BOTTOM : EventType::SCROLL_TO_BOTTOM); - break; - } - case MoveDirection::LEFT: - { - scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_LEFT : SCROLLVIEW_EVENT_SCROLL_TO_LEFT); - eventType = (bounce ? EventType::BOUNCE_LEFT : EventType::SCROLL_TO_LEFT); - break; - } - case MoveDirection::RIGHT: - { - scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_RIGHT : SCROLLVIEW_EVENT_SCROLL_TO_RIGHT); - eventType = (bounce ? EventType::BOUNCE_RIGHT : EventType::SCROLL_TO_RIGHT); - break; + case MoveDirection::TOP: + { + scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_TOP : SCROLLVIEW_EVENT_SCROLL_TO_TOP); + eventType = (bounce ? EventType::BOUNCE_TOP : EventType::SCROLL_TO_TOP); + break; + } + case MoveDirection::BOTTOM: + { + scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_BOTTOM : SCROLLVIEW_EVENT_SCROLL_TO_BOTTOM); + eventType = (bounce ? EventType::BOUNCE_BOTTOM : EventType::SCROLL_TO_BOTTOM); + break; + } + case MoveDirection::LEFT: + { + scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_LEFT : SCROLLVIEW_EVENT_SCROLL_TO_LEFT); + eventType = (bounce ? EventType::BOUNCE_LEFT : EventType::SCROLL_TO_LEFT); + break; + } + case MoveDirection::RIGHT: + { + scrollEventType = (bounce ? SCROLLVIEW_EVENT_BOUNCE_RIGHT : SCROLLVIEW_EVENT_SCROLL_TO_RIGHT); + eventType = (bounce ? EventType::BOUNCE_RIGHT : EventType::SCROLL_TO_RIGHT); + break; } } dispatchEvent(scrollEventType, eventType); From ecd947d9f437caa167f0e7b78f2b1baf90687469 Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Mon, 31 Aug 2015 12:36:05 +0900 Subject: [PATCH 5/7] Change auto scroll feature to receive callbacks to remove dependencies. --- cocos/ui/UIScrollView.cpp | 107 ++++++++++++++++++++++---------------- cocos/ui/UIScrollView.h | 4 +- 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index 95bdcb5b4c..ab6a487f4c 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -66,6 +66,8 @@ _autoScrolling(false), _autoScrollAttenuate(true), _autoScrollDuration(0), _autoScrollAccumulatedTime(0), +_autoScrollCompleteCallback(nullptr), +_autoScrollMoveCallback(nullptr), _bounceEnabled(false), _bouncingBack(false), _scrollBarEnabled(true), @@ -345,7 +347,29 @@ bool ScrollView::startBounceBackIfNeeded() } _bouncingBack = true; - startAutoScroll(outOfBoundary, BOUNCE_BACK_DURATION, true); + startAutoScroll(outOfBoundary, BOUNCE_BACK_DURATION, true, + [this](){ + _bouncingBack = false; + }, + [this](const Vec2& moveDelta) { + if(moveDelta.x > 0) + { + processScrollEvent(MoveDirection::RIGHT, true); + } + else if(moveDelta.x < 0) + { + processScrollEvent(MoveDirection::LEFT, true); + } + if(moveDelta.y > 0) + { + processScrollEvent(MoveDirection::TOP, true); + } + else if(moveDelta.y < 0) + { + processScrollEvent(MoveDirection::BOTTOM, true); + } + } + ); return true; } @@ -373,48 +397,6 @@ Vec2 ScrollView::getHowMuchOutOfBoundary(const Vec2& addition) const return result; } -void ScrollView::processAutoScrolling(float deltaTime) -{ - _autoScrollAccumulatedTime += deltaTime; - float percentage = _autoScrollAccumulatedTime / _autoScrollDuration; - if(percentage >= 1) - { - moveChildrenToPosition(_autoScrollStartPosition + _autoScrollTargetDelta); - _autoScrolling = false; - _bouncingBack = false; - } - else - { - if(_autoScrollAttenuate) - { - percentage = tweenfunc::quintEaseOut(percentage); - } - Vec2 moveDelta = _autoScrollTargetDelta * percentage; - moveChildrenToPosition(_autoScrollStartPosition + moveDelta); - - // Dispatch related events if bouncing - if(_bouncingBack) - { - if(moveDelta.x > 0) - { - processScrollEvent(MoveDirection::RIGHT, true); - } - else if(moveDelta.x < 0) - { - processScrollEvent(MoveDirection::LEFT, true); - } - if(moveDelta.y > 0) - { - processScrollEvent(MoveDirection::TOP, true); - } - else if(moveDelta.y < 0) - { - processScrollEvent(MoveDirection::BOTTOM, true); - } - } - } -} - bool ScrollView::isOutOfBoundary(MoveDirection dir) const { switch(dir) @@ -437,7 +419,12 @@ bool ScrollView::isOutOfBoundaryLeftOrRight() const return isOutOfBoundary(MoveDirection::LEFT) || isOutOfBoundary(MoveDirection::RIGHT); } -void ScrollView::startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated) +void ScrollView::startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated) +{ + startAutoScroll(des - _innerContainer->getPosition(), second, attenuated); +} + +void ScrollView::startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated, std::function completeCallback, std::function moveCallback) { _autoScrolling = true; _autoScrollTargetDelta = deltaMove; @@ -445,11 +432,39 @@ void ScrollView::startAutoScroll(const Vec2& deltaMove, float duration, bool att _autoScrollStartPosition = _innerContainer->getPosition(); _autoScrollDuration = duration; _autoScrollAccumulatedTime = 0; + _autoScrollCompleteCallback = completeCallback; + _autoScrollMoveCallback = moveCallback; } -void ScrollView::startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated) +void ScrollView::processAutoScrolling(float deltaTime) { - startAutoScroll(des - _innerContainer->getPosition(), second, attenuated); + _autoScrollAccumulatedTime += deltaTime; + + float percentage = _autoScrollAccumulatedTime / _autoScrollDuration; + if(percentage >= 1) + { + moveChildrenToPosition(_autoScrollStartPosition + _autoScrollTargetDelta); + _autoScrolling = false; + if(_autoScrollCompleteCallback) + { + _autoScrollCompleteCallback(); + } + return; + } + + if(_autoScrollAttenuate) + { + // Use quintic(5th degree) polynomial + percentage = tweenfunc::quintEaseOut(percentage); + } + + Vec2 moveDelta = _autoScrollTargetDelta * percentage; + moveChildrenToPosition(_autoScrollStartPosition + moveDelta); + + if(_autoScrollMoveCallback) + { + _autoScrollMoveCallback(moveDelta); + } } void ScrollView::jumpToDestination(const Vec2 &des) diff --git a/cocos/ui/UIScrollView.h b/cocos/ui/UIScrollView.h index 598087e33e..a386200af9 100644 --- a/cocos/ui/UIScrollView.h +++ b/cocos/ui/UIScrollView.h @@ -577,7 +577,7 @@ protected: void startInertiaScroll(const Vec2& touchMoveSpeed); void processInertiaScrolling(float dt); - void startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated); + void startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated, std::function completeCallback = nullptr, std::function moveCallback = nullptr); void startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated); void processAutoScrolling(float deltaTime); @@ -633,6 +633,8 @@ protected: Vec2 _autoScrollTargetDelta; float _autoScrollDuration; float _autoScrollAccumulatedTime; + std::function _autoScrollCompleteCallback; + std::function _autoScrollMoveCallback; bool _bounceEnabled; bool _bouncingBack; From 129f4b318669ab60b2fe114009dd63fce3d06a1a Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Mon, 31 Aug 2015 14:17:48 +0900 Subject: [PATCH 6/7] Implement the inertia scroll using auto scroll feature. Consolidate them into one. --- cocos/ui/UIScrollView.cpp | 158 +++++++++++++++----------------------- cocos/ui/UIScrollView.h | 20 +++-- 2 files changed, 73 insertions(+), 105 deletions(-) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index ab6a487f4c..ba08d7f865 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -31,9 +31,10 @@ THE SOFTWARE. #include "2d/CCCamera.h" NS_CC_BEGIN -static const float INERTIA_DEACCELERATION = 700.0f; -static const float INERTIA_VELOCITY_MAX = 2500; +static const float OUT_OF_BOUND_TIME_RESCALE = 0.05f; +static const float OUT_OF_BOUND_DISTANCE_RESCALE = 0.05f; static const float BOUNCE_BACK_DURATION = 1.0f; + #define MOVE_INCH 7.0f/160.0f static float convertDistanceFromPointToInch(const Vec2& dis) @@ -57,19 +58,17 @@ _leftBoundary(0.0f), _rightBoundary(0.0f), _bePressed(false), _childFocusCancelOffsetInInch(MOVE_INCH), -_inertiaScrollEnabled(true), -_inertiaScrolling(false), _touchMovePreviousTimestamp(0), -_inertiaScrollExpectedTime(0), -_inertiaScrollElapsedTime(0), _autoScrolling(false), _autoScrollAttenuate(true), _autoScrollDuration(0), _autoScrollAccumulatedTime(0), _autoScrollCompleteCallback(nullptr), _autoScrollMoveCallback(nullptr), +_outOfBoundaryDuringInertiaScroll(false), +_inertiaScrollEnabled(true), +_inertiaScrolling(false), _bounceEnabled(false), -_bouncingBack(false), _scrollBarEnabled(true), _verticalScrollBar(nullptr), _horizontalScrollBar(nullptr), @@ -346,11 +345,8 @@ bool ScrollView::startBounceBackIfNeeded() return false; } - _bouncingBack = true; startAutoScroll(outOfBoundary, BOUNCE_BACK_DURATION, true, - [this](){ - _bouncingBack = false; - }, + nullptr, [this](const Vec2& moveDelta) { if(moveDelta.x > 0) { @@ -419,6 +415,11 @@ bool ScrollView::isOutOfBoundaryLeftOrRight() const return isOutOfBoundary(MoveDirection::LEFT) || isOutOfBoundary(MoveDirection::RIGHT); } +bool ScrollView::isOutOfBoundary() const +{ + return isOutOfBoundaryTopOrBottom() || isOutOfBoundaryLeftOrRight(); +} + void ScrollView::startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated) { startAutoScroll(des - _innerContainer->getPosition(), second, attenuated); @@ -434,24 +435,30 @@ void ScrollView::startAutoScroll(const Vec2& deltaMove, float duration, bool att _autoScrollAccumulatedTime = 0; _autoScrollCompleteCallback = completeCallback; _autoScrollMoveCallback = moveCallback; + _outOfBoundaryDuringInertiaScroll = false; + _outOfBoundaryPositionDuringInertiaScroll = Vec2::ZERO; } void ScrollView::processAutoScrolling(float deltaTime) { - _autoScrollAccumulatedTime += deltaTime; + float timeRescale = 1; + float distanceRescale = 1; - float percentage = _autoScrollAccumulatedTime / _autoScrollDuration; - if(percentage >= 1) + // Shorten the auto scroll distance and time if it is out of boundary during inertia scroll. { - moveChildrenToPosition(_autoScrollStartPosition + _autoScrollTargetDelta); - _autoScrolling = false; - if(_autoScrollCompleteCallback) + bool currentlyOutOfBoundDuringInertiaScroll = (_inertiaScrolling && isOutOfBoundary()); + if(!_outOfBoundaryDuringInertiaScroll && currentlyOutOfBoundDuringInertiaScroll) { - _autoScrollCompleteCallback(); + _outOfBoundaryDuringInertiaScroll = true; + _outOfBoundaryPositionDuringInertiaScroll = getInnerContainerPosition(); } - return; + timeRescale = (_outOfBoundaryDuringInertiaScroll ? OUT_OF_BOUND_TIME_RESCALE : 1); + distanceRescale = (_outOfBoundaryDuringInertiaScroll ? OUT_OF_BOUND_DISTANCE_RESCALE : 1); } + _autoScrollAccumulatedTime += deltaTime * (1 / timeRescale); + + float percentage = MIN(1, _autoScrollAccumulatedTime / _autoScrollDuration); if(_autoScrollAttenuate) { // Use quintic(5th degree) polynomial @@ -459,12 +466,23 @@ void ScrollView::processAutoScrolling(float deltaTime) } Vec2 moveDelta = _autoScrollTargetDelta * percentage; - moveChildrenToPosition(_autoScrollStartPosition + moveDelta); + Vec2 newPosition = _autoScrollStartPosition + moveDelta; + newPosition = _outOfBoundaryPositionDuringInertiaScroll + (newPosition - _outOfBoundaryPositionDuringInertiaScroll) * distanceRescale; + moveChildrenToPosition(newPosition); if(_autoScrollMoveCallback) { _autoScrollMoveCallback(moveDelta); } + + if(percentage == 1) + { + _autoScrolling = false; + if(_autoScrollCompleteCallback) + { + _autoScrollCompleteCallback(); + } + } } void ScrollView::jumpToDestination(const Vec2 &des) @@ -482,7 +500,7 @@ void ScrollView::jumpToDestination(const Vec2 &des) moveChildrenToPosition(Vec2(finalOffsetX, finalOffsetY)); } -Vec2 ScrollView::calculateTouchMoveSpeed() const +Vec2 ScrollView::calculateTouchMoveVelocity() const { float totalDuration = 0; for(auto &timeDelta : _touchMoveTimeDeltas) @@ -502,55 +520,23 @@ Vec2 ScrollView::calculateTouchMoveSpeed() const return totalMovement / totalDuration; } -void ScrollView::startInertiaScroll(const Vec2& touchMoveSpeed) +void ScrollView::startInertiaScroll(const Vec2& touchMoveVelocity) { + Vec2 initialVelocity = touchMoveVelocity; + initialVelocity.x = (_direction == Direction::VERTICAL ? 0 : initialVelocity.x); + initialVelocity.y = (_direction == Direction::HORIZONTAL ? 0 : initialVelocity.y); + + const float MOVEMENT_FACTOR = 0.7f; + Vec2 inertiaTotalDisplacement = initialVelocity * MOVEMENT_FACTOR; + + // Calculate the duration from the initial velocity according to quintic polynomial. + float duration = sqrtf(sqrtf(initialVelocity.length() / 5)); + _inertiaScrolling = true; - - // Calcualte the initial velocity - _inertiaInitiVelocity = touchMoveSpeed; - _inertiaInitiVelocity.x = (_direction == Direction::VERTICAL ? 0 : _inertiaInitiVelocity.x); - _inertiaInitiVelocity.y = (_direction == Direction::HORIZONTAL ? 0 : _inertiaInitiVelocity.y); - - _inertiaInitiVelocity.x = MIN(_inertiaInitiVelocity.x, INERTIA_VELOCITY_MAX); - _inertiaInitiVelocity.y = MIN(_inertiaInitiVelocity.y, INERTIA_VELOCITY_MAX); - _inertiaInitiVelocity.x = MAX(_inertiaInitiVelocity.x, -INERTIA_VELOCITY_MAX); - _inertiaInitiVelocity.y = MAX(_inertiaInitiVelocity.y, -INERTIA_VELOCITY_MAX); - - // Calculate values for ease out - _inertiaScrollExpectedTime = _inertiaInitiVelocity.length() / INERTIA_DEACCELERATION; - _inertiaScrollElapsedTime = 0; -} - -void ScrollView::processInertiaScrolling(float dt) -{ - _inertiaScrollElapsedTime += dt; - if(isOutOfBoundaryLeftOrRight() || isOutOfBoundaryTopOrBottom()) - { - // If the inner container is out of boundary, shorten the inertia time. - _inertiaScrollElapsedTime += dt * (45000 / INERTIA_DEACCELERATION); - } - float percentage = _inertiaScrollElapsedTime / _inertiaScrollExpectedTime; - if(percentage >= 1) - { + startAutoScroll(inertiaTotalDisplacement, duration, true, [this]() { _inertiaScrolling = false; startBounceBackIfNeeded(); - return; - } - percentage = tweenfunc::quartEaseOut(percentage); - - Vec2 inertiaVelocity = _inertiaInitiVelocity * (1 - percentage); - Vec2 displacement = inertiaVelocity * dt; - if(!_bounceEnabled) - { - Vec2 outOfBoundary = getHowMuchOutOfBoundary(displacement); - if(outOfBoundary != Vec2::ZERO) - { - // Don't allow to go out of boundary - displacement += outOfBoundary; - _inertiaScrolling = false; - } - } - moveChildren(displacement.x, displacement.y); + }); } bool ScrollView::scrollChildren(float touchOffsetX, float touchOffsetY) @@ -826,6 +812,8 @@ void ScrollView::jumpToPercentBothDirection(const Vec2& percent) void ScrollView::handlePressLogic(Touch *touch) { _bePressed = true; + _autoScrolling = false; + _inertiaScrolling = false; // Initialize touch move information { @@ -834,20 +822,6 @@ void ScrollView::handlePressLogic(Touch *touch) _touchMoveTimeDeltas.clear(); } - if(_inertiaScrollEnabled) - { - if (_inertiaScrolling) - { - _inertiaScrolling = false; - } - } - - if(_autoScrolling) - { - _autoScrolling = false; - _bouncingBack = false; - } - if(_verticalScrollBar != nullptr) { _verticalScrollBar->onTouchBegan(); @@ -893,10 +867,10 @@ void ScrollView::handleReleaseLogic(Touch *touch) bool bounceBackStarted = startBounceBackIfNeeded(); if(!bounceBackStarted && _inertiaScrollEnabled) { - Vec2 touchMoveSpeed = calculateTouchMoveSpeed(); - if(touchMoveSpeed != Vec2::ZERO) + Vec2 touchMoveVelocity = calculateTouchMoveVelocity(); + if(touchMoveVelocity != Vec2::ZERO) { - startInertiaScroll(touchMoveSpeed); + startInertiaScroll(touchMoveVelocity); } } @@ -954,11 +928,7 @@ void ScrollView::onTouchCancelled(Touch *touch, Event *unusedEvent) void ScrollView::update(float dt) { - if (_inertiaScrolling) - { - processInertiaScrolling(dt); - } - else if (_autoScrolling) + if (_autoScrolling) { processAutoScrolling(dt); } @@ -1377,22 +1347,22 @@ void ScrollView::copySpecialProperties(Widget *widget) _rightBoundary = scrollView->_rightBoundary; _bePressed = scrollView->_bePressed; _childFocusCancelOffsetInInch = scrollView->_childFocusCancelOffsetInInch; - setInertiaScrollEnabled(scrollView->_inertiaScrollEnabled); - _inertiaScrolling = scrollView->_inertiaScrolling; - _inertiaInitiVelocity = scrollView->_inertiaInitiVelocity; _touchMoveDisplacements = scrollView->_touchMoveDisplacements; _touchMoveTimeDeltas = scrollView->_touchMoveTimeDeltas; _touchMovePreviousTimestamp = scrollView->_touchMovePreviousTimestamp; - _inertiaScrollExpectedTime = scrollView->_inertiaScrollExpectedTime; - _inertiaScrollElapsedTime = scrollView->_inertiaScrollElapsedTime; _autoScrolling = scrollView->_autoScrolling; _autoScrollAttenuate = scrollView->_autoScrollAttenuate; _autoScrollStartPosition = scrollView->_autoScrollStartPosition; _autoScrollTargetDelta = scrollView->_autoScrollTargetDelta; _autoScrollDuration = scrollView->_autoScrollDuration; _autoScrollAccumulatedTime = scrollView->_autoScrollAccumulatedTime; + _outOfBoundaryDuringInertiaScroll = scrollView->_outOfBoundaryDuringInertiaScroll; + _outOfBoundaryPositionDuringInertiaScroll = scrollView->_outOfBoundaryPositionDuringInertiaScroll; + _autoScrollCompleteCallback = scrollView->_autoScrollCompleteCallback; + _autoScrollMoveCallback = scrollView->_autoScrollMoveCallback; + setInertiaScrollEnabled(scrollView->_inertiaScrollEnabled); + _inertiaScrolling = scrollView->_inertiaScrolling; setBounceEnabled(scrollView->_bounceEnabled); - _bouncingBack = scrollView->_bouncingBack; _scrollViewEventListener = scrollView->_scrollViewEventListener; _scrollViewEventSelector = scrollView->_scrollViewEventSelector; _eventCallback = scrollView->_eventCallback; diff --git a/cocos/ui/UIScrollView.h b/cocos/ui/UIScrollView.h index a386200af9..f6a1247649 100644 --- a/cocos/ui/UIScrollView.h +++ b/cocos/ui/UIScrollView.h @@ -568,14 +568,14 @@ protected: bool isOutOfBoundary(MoveDirection dir) const; bool isOutOfBoundaryTopOrBottom() const; bool isOutOfBoundaryLeftOrRight() const; + bool isOutOfBoundary() const; void moveChildren(float offsetX, float offsetY); void moveChildrenToPosition(const Vec2& position); - Vec2 calculateTouchMoveSpeed() const; + Vec2 calculateTouchMoveVelocity() const; - void startInertiaScroll(const Vec2& touchMoveSpeed); - void processInertiaScrolling(float dt); + void startInertiaScroll(const Vec2& touchMoveVelocity); void startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated, std::function completeCallback = nullptr, std::function moveCallback = nullptr); void startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated); @@ -620,24 +620,22 @@ protected: std::list _touchMoveTimeDeltas; long long _touchMovePreviousTimestamp; - // Inertia scroll - bool _inertiaScrollEnabled; - bool _inertiaScrolling; - Vec2 _inertiaInitiVelocity; - float _inertiaScrollExpectedTime; - float _inertiaScrollElapsedTime; - bool _autoScrolling; bool _autoScrollAttenuate; Vec2 _autoScrollStartPosition; Vec2 _autoScrollTargetDelta; float _autoScrollDuration; float _autoScrollAccumulatedTime; + bool _outOfBoundaryDuringInertiaScroll; + Vec2 _outOfBoundaryPositionDuringInertiaScroll; std::function _autoScrollCompleteCallback; std::function _autoScrollMoveCallback; + // Inertia scroll + bool _inertiaScrollEnabled; + bool _inertiaScrolling; + bool _bounceEnabled; - bool _bouncingBack; bool _scrollBarEnabled; ScrollViewBar* _verticalScrollBar; From 3656ce99bd11e3982314daedc545112f3737c7a9 Mon Sep 17 00:00:00 2001 From: Neo Kim Date: Tue, 1 Sep 2015 15:12:27 +0900 Subject: [PATCH 7/7] Fix an issue regarding non-bouncing scroll view --- cocos/ui/UIScrollView.cpp | 49 ++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/cocos/ui/UIScrollView.cpp b/cocos/ui/UIScrollView.cpp index ba08d7f865..34f405b159 100644 --- a/cocos/ui/UIScrollView.cpp +++ b/cocos/ui/UIScrollView.cpp @@ -441,10 +441,9 @@ void ScrollView::startAutoScroll(const Vec2& deltaMove, float duration, bool att void ScrollView::processAutoScrolling(float deltaTime) { + // Shorten the auto scroll distance and time if it is out of boundary during inertia scroll. float timeRescale = 1; float distanceRescale = 1; - - // Shorten the auto scroll distance and time if it is out of boundary during inertia scroll. { bool currentlyOutOfBoundDuringInertiaScroll = (_inertiaScrolling && isOutOfBoundary()); if(!_outOfBoundaryDuringInertiaScroll && currentlyOutOfBoundDuringInertiaScroll) @@ -456,26 +455,50 @@ void ScrollView::processAutoScrolling(float deltaTime) distanceRescale = (_outOfBoundaryDuringInertiaScroll ? OUT_OF_BOUND_DISTANCE_RESCALE : 1); } - _autoScrollAccumulatedTime += deltaTime * (1 / timeRescale); - - float percentage = MIN(1, _autoScrollAccumulatedTime / _autoScrollDuration); - if(_autoScrollAttenuate) + // Calculate the percentage + float percentage = 0; { - // Use quintic(5th degree) polynomial - percentage = tweenfunc::quintEaseOut(percentage); + _autoScrollAccumulatedTime += deltaTime * (1 / timeRescale); + percentage = MIN(1, _autoScrollAccumulatedTime / _autoScrollDuration); + if(_autoScrollAttenuate) + { + // Use quintic(5th degree) polynomial + percentage = tweenfunc::quintEaseOut(percentage); + } } - Vec2 moveDelta = _autoScrollTargetDelta * percentage; - Vec2 newPosition = _autoScrollStartPosition + moveDelta; - newPosition = _outOfBoundaryPositionDuringInertiaScroll + (newPosition - _outOfBoundaryPositionDuringInertiaScroll) * distanceRescale; + // Calculate the new position + Vec2 deltaFromInitialPosition = _autoScrollTargetDelta * percentage; + Vec2 newPosition = _autoScrollStartPosition + deltaFromInitialPosition; + bool reachedEnd = false; + + // Adjust the new position according to the bounce opiton + { + if(_bounceEnabled) + { + newPosition = _outOfBoundaryPositionDuringInertiaScroll + (newPosition - _outOfBoundaryPositionDuringInertiaScroll) * distanceRescale; + } + else + { + Vec2 moveDelta = newPosition - getInnerContainerPosition(); + Vec2 outOfBoundary = getHowMuchOutOfBoundary(moveDelta); + if(outOfBoundary != Vec2::ZERO) + { + newPosition += outOfBoundary; + reachedEnd = true; + } + } + } moveChildrenToPosition(newPosition); + if(_autoScrollMoveCallback) { - _autoScrollMoveCallback(moveDelta); + _autoScrollMoveCallback(getInnerContainerPosition() - newPosition); } - if(percentage == 1) + // Finish auto scroll if it ended + if(percentage == 1 || reachedEnd) { _autoScrolling = false; if(_autoScrollCompleteCallback)