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); }
void ScrollView::moveInnerContainer(const Vec2& deltaMove, bool canStartBounceBack) { Vec2 adjustedMove = flattenVectorByDirection(deltaMove); setInnerContainerPosition(getInnerContainerPosition() + adjustedMove); Vec2 outOfBoundary = getHowMuchOutOfBoundary(); updateScrollBar(outOfBoundary); if(_bounceEnabled && canStartBounceBack) { startBounceBackIfNeeded(); } }
void ListView::jumpToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint) { Widget* item = getItem(itemIndex); if (item == nullptr) { return; } doLayout(); Vec2 destination = calculateItemDestination(positionRatioInView, item, itemAnchorPoint); if(!_bounceEnabled) { Vec2 delta = destination - getInnerContainerPosition(); Vec2 outOfBoundary = getHowMuchOutOfBoundary(delta); destination += outOfBoundary; } jumpToDestination(destination); }
bool ScrollView::isNecessaryAutoScrollBrake() { if(_autoScrollBraking) { return true; } if(isOutOfBoundary()) { // It just went out of boundary. if(!_autoScrollCurrentlyOutOfBoundary) { _autoScrollCurrentlyOutOfBoundary = true; _autoScrollBraking = true; _autoScrollBrakingStartPosition = getInnerContainerPosition(); return true; } } else { _autoScrollCurrentlyOutOfBoundary = false; } return false; }
void ScrollView::jumpToDestination(const Vec2 &des) { _autoScrolling = false; moveInnerContainer(des - getInnerContainerPosition(), true); }
float ScrollView::getScrolledPercentHorizontal() const { const float minX = getContentSize().width - getInnerContainerSize().width; return getInnerContainerPosition().x / minX * 100.f; }
float ScrollView::getScrolledPercentVertical() const { const float minY = getContentSize().height - getInnerContainerSize().height; return (1.f - getInnerContainerPosition().y / minY)*100.f; }