void ScrollView::startAutoScroll(const Vec2& deltaMove, float timeInSec, bool attenuated) { Vec2 adjustedDeltaMove = flattenVectorByDirection(deltaMove); _autoScrolling = true; _autoScrollTargetDelta = adjustedDeltaMove; _autoScrollAttenuate = attenuated; _autoScrollStartPosition = _innerContainer->getPosition(); _autoScrollTotalTime = timeInSec; _autoScrollAccumulatedTime = 0; _autoScrollBraking = false; _autoScrollBrakingStartPosition = Vec2::ZERO; // If the destination is also out of boundary of same side, start brake from beginning. Vec2 currentOutOfBoundary = getHowMuchOutOfBoundary(); if (!fltEqualZero(currentOutOfBoundary)) { _autoScrollCurrentlyOutOfBoundary = true; Vec2 afterOutOfBoundary = getHowMuchOutOfBoundary(adjustedDeltaMove); if(currentOutOfBoundary.x * afterOutOfBoundary.x > 0 || currentOutOfBoundary.y * afterOutOfBoundary.y > 0) { _autoScrollBraking = true; } } }
void ScrollView::processAutoScrolling(float deltaTime) { // Make auto scroll shorter if it needs to deaccelerate. float brakingFactor = (isNecessaryAutoScrollBrake() ? OUT_OF_BOUNDARY_BREAKING_FACTOR : 1); // Elapsed time _autoScrollAccumulatedTime += deltaTime * (1 / brakingFactor); // Calculate the progress percentage float percentage = MIN(1, _autoScrollAccumulatedTime / _autoScrollTotalTime); if(_autoScrollAttenuate) { // Use quintic(5th degree) polynomial percentage = tweenfunc::quintEaseOut(percentage); } // Calculate the new position Vec2 newPosition = _autoScrollStartPosition + (_autoScrollTargetDelta * percentage); bool reachedEnd = std::abs(percentage - 1) <= this->getAutoScrollStopEpsilon(); if (reachedEnd) { newPosition = _autoScrollStartPosition + _autoScrollTargetDelta; } if(_bounceEnabled) { // The new position is adjusted if out of boundary newPosition = _autoScrollBrakingStartPosition + (newPosition - _autoScrollBrakingStartPosition) * brakingFactor; } else { // Don't let go out of boundary Vec2 moveDelta = newPosition - getInnerContainerPosition(); Vec2 outOfBoundary = getHowMuchOutOfBoundary(moveDelta); if (!fltEqualZero(outOfBoundary)) { newPosition += outOfBoundary; reachedEnd = true; } } // Finish auto scroll if it ended if(reachedEnd) { _autoScrolling = false; dispatchEvent(SCROLLVIEW_EVENT_AUTOSCROLL_ENDED, EventType::AUTOSCROLL_ENDED); } moveInnerContainer(newPosition - getInnerContainerPosition(), reachedEnd); }
bool ScrollView::startBounceBackIfNeeded() { if (!_bounceEnabled) { return false; } Vec2 bounceBackAmount = getHowMuchOutOfBoundary(); if(fltEqualZero(bounceBackAmount)) { return false; } startAutoScroll(bounceBackAmount, BOUNCE_BACK_DURATION, true); return true; }
bool ScrollView::isOutOfBoundary() { return !fltEqualZero(getHowMuchOutOfBoundary()); }