mirror of https://github.com/axmolengine/axmol.git
Merge branch 'feature/elastic_inertia_scroll' into feature/elastic_scrollview
Apply elastic movement to inertia scroll
This commit is contained in:
commit
ff5dbd5a52
|
@ -29,38 +29,16 @@ NS_CC_BEGIN
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
static const float AUTOSCROLLMAXSPEED = 1000.0f;
|
static const float INERTIA_DEACCELERATION = 3000.0f;
|
||||||
|
|
||||||
static const float BOUNCE_BACK_DURATION = 0.3f;
|
static const float BOUNCE_BACK_DURATION = 0.3f;
|
||||||
|
|
||||||
|
static long long getTimestamp()
|
||||||
static char LOG_BUFFER[256];
|
|
||||||
char* time()
|
|
||||||
{
|
{
|
||||||
int nBufferLength = 256;
|
|
||||||
// Get current local time
|
|
||||||
struct tm* ptm = NULL;
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
{
|
|
||||||
gettimeofday (&tv, NULL);
|
gettimeofday (&tv, NULL);
|
||||||
ptm = localtime (&tv.tv_sec);
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the date and time, down to a single second.
|
|
||||||
strftime (LOG_BUFFER, nBufferLength, "%Y-%m-%d %H:%M:%S", ptm);
|
|
||||||
size_t nCurrentLength = strlen(LOG_BUFFER);
|
|
||||||
|
|
||||||
// Compute milliseconds from microseconds.
|
|
||||||
long lMilliseconds = tv.tv_usec / 1000;
|
|
||||||
snprintf(LOG_BUFFER + nCurrentLength, nBufferLength - nCurrentLength, ".%03ld", lMilliseconds);
|
|
||||||
return LOG_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vec2 SCROLLDIR_UP(0.0f, 1.0f);
|
|
||||||
const Vec2 SCROLLDIR_DOWN(0.0f, -1.0f);
|
|
||||||
const Vec2 SCROLLDIR_LEFT(-1.0f, 0.0f);
|
|
||||||
const Vec2 SCROLLDIR_RIGHT(1.0f, 0.0f);
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS_GUI_INFO(ScrollView)
|
IMPLEMENT_CLASS_GUI_INFO(ScrollView)
|
||||||
|
|
||||||
ScrollView::ScrollView():
|
ScrollView::ScrollView():
|
||||||
|
@ -70,21 +48,19 @@ _topBoundary(0.0f),
|
||||||
_bottomBoundary(0.0f),
|
_bottomBoundary(0.0f),
|
||||||
_leftBoundary(0.0f),
|
_leftBoundary(0.0f),
|
||||||
_rightBoundary(0.0f),
|
_rightBoundary(0.0f),
|
||||||
_autoScroll(false),
|
|
||||||
_autoScrollAddUpTime(0.0f),
|
|
||||||
_autoScrollOriginalSpeed(0.0f),
|
|
||||||
_autoScrollAcceleration(-1000.0f),
|
|
||||||
_isAutoScrollSpeedAttenuated(false),
|
|
||||||
_needCheckAutoScrollDestination(false),
|
|
||||||
_bePressed(false),
|
_bePressed(false),
|
||||||
_slidTime(0.0f),
|
|
||||||
_childFocusCancelOffset(5.0f),
|
_childFocusCancelOffset(5.0f),
|
||||||
|
_inertiaScrollEnabled(true),
|
||||||
|
_inertiaScrolling(false),
|
||||||
|
_inertiaPrevTouchTimestamp(0),
|
||||||
|
_inertiaScrollExpectedTime(0),
|
||||||
|
_inertiaScrollElapsedTime(0),
|
||||||
|
_autoScrolling(false),
|
||||||
|
_autoScrollAttenuate(true),
|
||||||
|
_autoScrollDuration(0),
|
||||||
|
_autoScrollAccumulatedTime(0),
|
||||||
_bounceEnabled(false),
|
_bounceEnabled(false),
|
||||||
_bouncingBack(false),
|
_bouncingBack(false),
|
||||||
_bounceBackAttenuate(true),
|
|
||||||
_bounceBackDuration(0),
|
|
||||||
_bounceBackAccumulatedTime(0),
|
|
||||||
_inertiaScrollEnabled(true),
|
|
||||||
_scrollViewEventListener(nullptr),
|
_scrollViewEventListener(nullptr),
|
||||||
_scrollViewEventSelector(nullptr),
|
_scrollViewEventSelector(nullptr),
|
||||||
_eventCallback(nullptr)
|
_eventCallback(nullptr)
|
||||||
|
@ -289,56 +265,6 @@ void ScrollView::moveChildren(float offsetX, float offsetY)
|
||||||
_innerContainer->setPosition(position);
|
_innerContainer->setPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::autoScrollChildren(float dt)
|
|
||||||
{
|
|
||||||
float lastTime = _autoScrollAddUpTime;
|
|
||||||
_autoScrollAddUpTime += dt;
|
|
||||||
if (_isAutoScrollSpeedAttenuated)
|
|
||||||
{
|
|
||||||
float nowSpeed = _autoScrollOriginalSpeed + _autoScrollAcceleration * _autoScrollAddUpTime;
|
|
||||||
if (nowSpeed <= 0.0f)
|
|
||||||
{
|
|
||||||
stopAutoScrollChildren();
|
|
||||||
startBounceBackIfNeeded();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float timeParam = lastTime * 2 + dt;
|
|
||||||
float offset = (_autoScrollOriginalSpeed + _autoScrollAcceleration * timeParam * 0.5f) * dt;
|
|
||||||
float offsetX = offset * _autoScrollDir.x;
|
|
||||||
float offsetY = offset * _autoScrollDir.y;
|
|
||||||
if (!scrollChildren(offsetX, offsetY))
|
|
||||||
{
|
|
||||||
stopAutoScrollChildren();
|
|
||||||
startBounceBackIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_needCheckAutoScrollDestination)
|
|
||||||
{
|
|
||||||
float xOffset = _autoScrollDir.x * dt * _autoScrollOriginalSpeed;
|
|
||||||
float yOffset = _autoScrollDir.y * dt * _autoScrollOriginalSpeed;
|
|
||||||
bool notDone = checkCustomScrollDestination(&xOffset, &yOffset);
|
|
||||||
bool scrollCheck = scrollChildren(xOffset, yOffset);
|
|
||||||
if (!notDone || !scrollCheck)
|
|
||||||
{
|
|
||||||
stopAutoScrollChildren();
|
|
||||||
startBounceBackIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!scrollChildren(_autoScrollDir.x * dt * _autoScrollOriginalSpeed, _autoScrollDir.y * dt * _autoScrollOriginalSpeed))
|
|
||||||
{
|
|
||||||
stopAutoScrollChildren();
|
|
||||||
startBounceBackIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScrollView::startBounceBackIfNeeded()
|
bool ScrollView::startBounceBackIfNeeded()
|
||||||
{
|
{
|
||||||
if (!_bounceEnabled)
|
if (!_bounceEnabled)
|
||||||
|
@ -346,18 +272,14 @@ bool ScrollView::startBounceBackIfNeeded()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_bounceBackTargetDelta = getHowMuchOutOfBoundary(Vec2::ZERO);
|
Vec2 outOfBoundary = getHowMuchOutOfBoundary(Vec2::ZERO);
|
||||||
if(_bounceBackTargetDelta == Vec2::ZERO)
|
if(outOfBoundary == Vec2::ZERO)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_bouncingBack = true;
|
_bouncingBack = true;
|
||||||
_bounceBackAttenuate = true;
|
startAutoScroll(outOfBoundary, BOUNCE_BACK_DURATION, true);
|
||||||
_bounceBackStartPosition = _innerContainer->getPosition();
|
|
||||||
_bounceBackDuration = DEFAULT_BOUNCE_BACK_DURATION;
|
|
||||||
_bounceBackAccumulatedTime = 0;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,24 +307,27 @@ Vec2 ScrollView::getHowMuchOutOfBoundary(const Vec2& addition) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::processBounceBack(float deltaTime)
|
void ScrollView::processAutoScrolling(float deltaTime)
|
||||||
{
|
{
|
||||||
_bounceBackAccumulatedTime += deltaTime;
|
_autoScrollAccumulatedTime += deltaTime;
|
||||||
float percentage = _bounceBackAccumulatedTime / _bounceBackDuration;
|
float percentage = _autoScrollAccumulatedTime / _autoScrollDuration;
|
||||||
if(percentage >= 1)
|
if(percentage >= 1)
|
||||||
{
|
{
|
||||||
_innerContainer->setPosition(_bounceBackStartPosition + _bounceBackTargetDelta);
|
_innerContainer->setPosition(_autoScrollStartPosition + _autoScrollTargetDelta);
|
||||||
|
_autoScrolling = false;
|
||||||
_bouncingBack = false;
|
_bouncingBack = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(_bounceBackAttenuate)
|
if(_autoScrollAttenuate)
|
||||||
{
|
{
|
||||||
percentage = tweenfunc::expoEaseOut(percentage);
|
percentage = tweenfunc::expoEaseOut(percentage);
|
||||||
}
|
}
|
||||||
Vec2 moveDelta = _bounceBackTargetDelta * percentage;
|
Vec2 moveDelta = _autoScrollTargetDelta * percentage;
|
||||||
|
|
||||||
// Dispatch related events
|
// Dispatch related events if bouncing
|
||||||
|
if(_bouncingBack)
|
||||||
|
{
|
||||||
if(moveDelta.x > 0)
|
if(moveDelta.x > 0)
|
||||||
{
|
{
|
||||||
processScrollEvent(MoveDirection::RIGHT, true);
|
processScrollEvent(MoveDirection::RIGHT, true);
|
||||||
|
@ -419,7 +344,8 @@ void ScrollView::processBounceBack(float deltaTime)
|
||||||
{
|
{
|
||||||
processScrollEvent(MoveDirection::BOTTOM, true);
|
processScrollEvent(MoveDirection::BOTTOM, true);
|
||||||
}
|
}
|
||||||
_innerContainer->setPosition(_bounceBackStartPosition + moveDelta);
|
}
|
||||||
|
_innerContainer->setPosition(_autoScrollStartPosition + moveDelta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,35 +370,19 @@ bool ScrollView::isOutOfBoundaryLeftOrRight() const
|
||||||
return isOutOfBoundary(MoveDirection::LEFT) || isOutOfBoundary(MoveDirection::RIGHT);
|
return isOutOfBoundary(MoveDirection::LEFT) || isOutOfBoundary(MoveDirection::RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::startAutoScrollChildrenWithOriginalSpeed(const Vec2& dir, float v, bool attenuated, float acceleration)
|
void ScrollView::startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated)
|
||||||
{
|
{
|
||||||
stopAutoScrollChildren();
|
_autoScrolling = true;
|
||||||
_autoScrollDir = dir;
|
_autoScrollTargetDelta = deltaMove;
|
||||||
_isAutoScrollSpeedAttenuated = attenuated;
|
_autoScrollAttenuate = attenuated;
|
||||||
_autoScrollOriginalSpeed = v;
|
_autoScrollStartPosition = _innerContainer->getPosition();
|
||||||
_autoScroll = true;
|
_autoScrollDuration = duration;
|
||||||
_autoScrollAcceleration = acceleration;
|
_autoScrollAccumulatedTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated)
|
void ScrollView::startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated)
|
||||||
{
|
{
|
||||||
_needCheckAutoScrollDestination = false;
|
startAutoScroll(des - _innerContainer->getPosition(), second, attenuated);
|
||||||
_autoScrollDestination = des;
|
|
||||||
Vec2 dis = des - _innerContainer->getPosition();
|
|
||||||
Vec2 dir = dis.getNormalized();
|
|
||||||
float orSpeed = 0.0f;
|
|
||||||
float acceleration = -1000.0f;
|
|
||||||
if (attenuated)
|
|
||||||
{
|
|
||||||
acceleration = (-(2 * dis.getLength())) / (second * second);
|
|
||||||
orSpeed = 2 * dis.getLength() / second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_needCheckAutoScrollDestination = true;
|
|
||||||
orSpeed = dis.getLength() / second;
|
|
||||||
}
|
|
||||||
startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, attenuated, acceleration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::jumpToDestination(const Vec2 &des)
|
void ScrollView::jumpToDestination(const Vec2 &des)
|
||||||
|
@ -490,137 +400,71 @@ void ScrollView::jumpToDestination(const Vec2 &des)
|
||||||
_innerContainer->setPosition(Vec2(finalOffsetX, finalOffsetY));
|
_innerContainer->setPosition(Vec2(finalOffsetX, finalOffsetY));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::stopAutoScrollChildren()
|
void ScrollView::startInertiaScroll()
|
||||||
{
|
{
|
||||||
_autoScroll = false;
|
if(_inertiaTouchTimeDeltas.empty())
|
||||||
_autoScrollOriginalSpeed = 0.0f;
|
{
|
||||||
_autoScrollAddUpTime = 0.0f;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScrollView::checkCustomScrollDestinationLeft(float* touchOffsetX, float* touchOffsetY)
|
float totalDuration = 0;
|
||||||
|
for(auto i = _inertiaTouchTimeDeltas.begin(); i != _inertiaTouchTimeDeltas.end(); ++i)
|
||||||
{
|
{
|
||||||
float icLeftPos = _innerContainer->getLeftBoundary();
|
totalDuration += (*i);
|
||||||
if (icLeftPos + *touchOffsetX >= _autoScrollDestination.x)
|
|
||||||
{
|
|
||||||
*touchOffsetX = _autoScrollDestination.x - icLeftPos;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
if(totalDuration >= 0.5f)
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScrollView::checkCustomScrollDestinationRight(float* touchOffsetX, float* touchOffsetY)
|
_inertiaScrolling = true;
|
||||||
|
|
||||||
|
// Calcualte the initial velocity
|
||||||
|
Vec2 totalMovement;
|
||||||
|
for(auto i = _inertiaTouchDisplacements.begin(); i != _inertiaTouchDisplacements.end(); ++i)
|
||||||
{
|
{
|
||||||
float icRightPos = _innerContainer->getRightBoundary();
|
totalMovement += (*i);
|
||||||
if (icRightPos + *touchOffsetX <= _autoScrollDestination.x)
|
|
||||||
{
|
|
||||||
*touchOffsetX = _autoScrollDestination.x - icRightPos;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
totalMovement.x = (_direction == Direction::VERTICAL ? 0 : totalMovement.x);
|
||||||
|
totalMovement.y = (_direction == Direction::HORIZONTAL ? 0 : totalMovement.y);
|
||||||
|
|
||||||
|
_inertiaInitiVelocity = totalMovement / totalDuration;
|
||||||
|
|
||||||
|
// Calculate values for ease out
|
||||||
|
_inertiaScrollExpectedTime = _inertiaInitiVelocity.length() / INERTIA_DEACCELERATION;
|
||||||
|
_inertiaScrollElapsedTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScrollView::checkCustomScrollDestination(float* touchOffsetX, float* touchOffsetY)
|
void ScrollView::processInertiaScrolling(float dt)
|
||||||
{
|
{
|
||||||
bool scrollenabled = true;
|
_inertiaScrollElapsedTime += dt;
|
||||||
switch (_direction)
|
if(isOutOfBoundaryLeftOrRight() || isOutOfBoundaryTopOrBottom())
|
||||||
{
|
{
|
||||||
case Direction::VERTICAL:
|
// If the inner container is out of boundary, shorten the inertia time.
|
||||||
|
_inertiaScrollElapsedTime += dt * 15;
|
||||||
|
}
|
||||||
|
float percentage = _inertiaScrollElapsedTime / _inertiaScrollExpectedTime;
|
||||||
|
if(percentage >= 1)
|
||||||
{
|
{
|
||||||
if (_autoScrollDir.y > 0)
|
_inertiaScrolling = false;
|
||||||
|
startBounceBackIfNeeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
percentage = tweenfunc::expoEaseOut(percentage);
|
||||||
|
|
||||||
|
Vec2 inertiaVelocity = _inertiaInitiVelocity * (1 - percentage);
|
||||||
|
Vec2 displacement = inertiaVelocity * dt;
|
||||||
|
if(!_bounceEnabled)
|
||||||
{
|
{
|
||||||
float icBottomPos = _innerContainer->getBottomBoundary();
|
Vec2 outOfBoundary = getHowMuchOutOfBoundary(displacement);
|
||||||
if (icBottomPos + *touchOffsetY >= _autoScrollDestination.y)
|
if(outOfBoundary != Vec2::ZERO)
|
||||||
{
|
{
|
||||||
*touchOffsetY = _autoScrollDestination.y - icBottomPos;
|
// Don't allow to go out of boundary
|
||||||
scrollenabled = false;
|
displacement += outOfBoundary;
|
||||||
|
_inertiaScrolling = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
moveChildren(displacement.x, displacement.y);
|
||||||
{
|
|
||||||
float icBottomPos = _innerContainer->getBottomBoundary();
|
|
||||||
if (icBottomPos + *touchOffsetY <= _autoScrollDestination.y)
|
|
||||||
{
|
|
||||||
*touchOffsetY = _autoScrollDestination.y - icBottomPos;
|
|
||||||
scrollenabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::HORIZONTAL:
|
|
||||||
{
|
|
||||||
if (_autoScrollDir.x > 0)
|
|
||||||
{
|
|
||||||
float icLeftPos = _innerContainer->getLeftBoundary();
|
|
||||||
if (icLeftPos + *touchOffsetX >= _autoScrollDestination.x)
|
|
||||||
{
|
|
||||||
*touchOffsetX = _autoScrollDestination.x - icLeftPos;
|
|
||||||
scrollenabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float icLeftPos = _innerContainer->getLeftBoundary();
|
|
||||||
if (icLeftPos + *touchOffsetX <= _autoScrollDestination.x)
|
|
||||||
{
|
|
||||||
*touchOffsetX = _autoScrollDestination.x - icLeftPos;
|
|
||||||
scrollenabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::BOTH:
|
|
||||||
{
|
|
||||||
if (*touchOffsetY > 0.0f) // up
|
|
||||||
{
|
|
||||||
if (*touchOffsetX > 0.0f) // right
|
|
||||||
{
|
|
||||||
scrollenabled = checkCustomScrollDestinationLeft(touchOffsetX, touchOffsetY);
|
|
||||||
}
|
|
||||||
else if (*touchOffsetX < 0.0f) // left
|
|
||||||
{
|
|
||||||
scrollenabled = checkCustomScrollDestinationRight(touchOffsetX, touchOffsetY);
|
|
||||||
}
|
|
||||||
float icBottomPos = _innerContainer->getBottomBoundary();
|
|
||||||
if (icBottomPos + *touchOffsetY >= _autoScrollDestination.y)
|
|
||||||
{
|
|
||||||
*touchOffsetY = _autoScrollDestination.y - icBottomPos;
|
|
||||||
scrollenabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*touchOffsetY < 0.0f) // down
|
|
||||||
{
|
|
||||||
if (*touchOffsetX < 0.0f) // left
|
|
||||||
{
|
|
||||||
scrollenabled = checkCustomScrollDestinationRight(touchOffsetX, touchOffsetY);
|
|
||||||
}
|
|
||||||
else if (*touchOffsetX > 0.0f) // right
|
|
||||||
{
|
|
||||||
scrollenabled = checkCustomScrollDestinationLeft(touchOffsetX, touchOffsetY);
|
|
||||||
}
|
|
||||||
float icTopPos = _innerContainer->getTopBoundary();
|
|
||||||
if (icTopPos + *touchOffsetY <= _autoScrollDestination.y)
|
|
||||||
{
|
|
||||||
*touchOffsetY = _autoScrollDestination.y - icTopPos;
|
|
||||||
scrollenabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (*touchOffsetX < 0.0f) // left
|
|
||||||
{
|
|
||||||
scrollenabled = checkCustomScrollDestinationRight(touchOffsetX, touchOffsetY);
|
|
||||||
}
|
|
||||||
else if (*touchOffsetX > 0.0f) // right
|
|
||||||
{
|
|
||||||
scrollenabled = checkCustomScrollDestinationLeft(touchOffsetX, touchOffsetY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return scrollenabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScrollView::processScrollUp(float* offsetYResult, float touchOffsetY)
|
bool ScrollView::processScrollUp(float* offsetYResult, float touchOffsetY)
|
||||||
|
@ -899,66 +743,23 @@ void ScrollView::jumpToPercentBothDirection(const Vec2& percent)
|
||||||
|
|
||||||
void ScrollView::startRecordSlidAction()
|
void ScrollView::startRecordSlidAction()
|
||||||
{
|
{
|
||||||
if (_autoScroll)
|
if (_inertiaScrolling)
|
||||||
{
|
{
|
||||||
stopAutoScrollChildren();
|
_inertiaScrolling = false;
|
||||||
}
|
}
|
||||||
if (_bouncingBack)
|
if(_autoScrolling)
|
||||||
{
|
{
|
||||||
|
_autoScrolling = false;
|
||||||
_bouncingBack = false;
|
_bouncingBack = false;
|
||||||
}
|
}
|
||||||
_slidTime = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::endRecordSlidAction()
|
void ScrollView::endRecordSlidAction()
|
||||||
{
|
{
|
||||||
if (!startBounceBackIfNeeded() && _inertiaScrollEnabled)
|
bool bounceBackStarted = startBounceBackIfNeeded();
|
||||||
|
if(!bounceBackStarted && _inertiaScrollEnabled)
|
||||||
{
|
{
|
||||||
if (_slidTime <= 0.016f)
|
startInertiaScroll();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float totalDis = 0.0f;
|
|
||||||
Vec2 dir;
|
|
||||||
Vec2 touchEndPositionInNodeSpace = this->convertToNodeSpace(_touchEndPosition);
|
|
||||||
Vec2 touchBeganPositionInNodeSpace = this->convertToNodeSpace(_touchBeganPosition);
|
|
||||||
switch (_direction)
|
|
||||||
{
|
|
||||||
case Direction::VERTICAL:
|
|
||||||
totalDis = touchEndPositionInNodeSpace.y - touchBeganPositionInNodeSpace.y;
|
|
||||||
if (totalDis < 0.0f)
|
|
||||||
{
|
|
||||||
dir = SCROLLDIR_DOWN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = SCROLLDIR_UP;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Direction::HORIZONTAL:
|
|
||||||
totalDis = touchEndPositionInNodeSpace.x - touchBeganPositionInNodeSpace.x;
|
|
||||||
if (totalDis < 0.0f)
|
|
||||||
{
|
|
||||||
dir = SCROLLDIR_LEFT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = SCROLLDIR_RIGHT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Direction::BOTH:
|
|
||||||
{
|
|
||||||
Vec2 subVector = touchEndPositionInNodeSpace - touchBeganPositionInNodeSpace;
|
|
||||||
totalDis = subVector.getLength();
|
|
||||||
dir = subVector.getNormalized();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
float orSpeed = MIN(fabs(totalDis)/(_slidTime), AUTOSCROLLMAXSPEED);
|
|
||||||
startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, true, -1000);
|
|
||||||
_slidTime = 0.0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,6 +767,10 @@ void ScrollView::handlePressLogic(Touch *touch)
|
||||||
{
|
{
|
||||||
startRecordSlidAction();
|
startRecordSlidAction();
|
||||||
_bePressed = true;
|
_bePressed = true;
|
||||||
|
|
||||||
|
_inertiaPrevTouchTimestamp = getTimestamp();
|
||||||
|
_inertiaTouchDisplacements.clear();
|
||||||
|
_inertiaTouchTimeDeltas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::handleMoveLogic(Touch *touch)
|
void ScrollView::handleMoveLogic(Touch *touch)
|
||||||
|
@ -974,6 +779,17 @@ void ScrollView::handleMoveLogic(Touch *touch)
|
||||||
Vec2 previousTouchPositionInNodeSpace = this->convertToNodeSpace(touch->getPreviousLocation());
|
Vec2 previousTouchPositionInNodeSpace = this->convertToNodeSpace(touch->getPreviousLocation());
|
||||||
Vec2 delta = touchPositionInNodeSpace - previousTouchPositionInNodeSpace;
|
Vec2 delta = touchPositionInNodeSpace - previousTouchPositionInNodeSpace;
|
||||||
scrollChildren(delta.x, delta.y);
|
scrollChildren(delta.x, delta.y);
|
||||||
|
|
||||||
|
while(_inertiaTouchDisplacements.size() > 5)
|
||||||
|
{
|
||||||
|
_inertiaTouchDisplacements.pop_front();
|
||||||
|
_inertiaTouchTimeDeltas.pop_front();
|
||||||
|
}
|
||||||
|
_inertiaTouchDisplacements.push_back(delta);
|
||||||
|
|
||||||
|
long long timestamp = getTimestamp();
|
||||||
|
_inertiaTouchTimeDeltas.push_back((timestamp - _inertiaPrevTouchTimestamp) / 1000.0f);
|
||||||
|
_inertiaPrevTouchTimestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollView::handleReleaseLogic(Touch *touch)
|
void ScrollView::handleReleaseLogic(Touch *touch)
|
||||||
|
@ -1026,22 +842,13 @@ void ScrollView::onTouchCancelled(Touch *touch, Event *unusedEvent)
|
||||||
|
|
||||||
void ScrollView::update(float dt)
|
void ScrollView::update(float dt)
|
||||||
{
|
{
|
||||||
if (_autoScroll)
|
if (_inertiaScrolling)
|
||||||
{
|
{
|
||||||
autoScrollChildren(dt);
|
processInertiaScrolling(dt);
|
||||||
}
|
}
|
||||||
if(_bouncingBack)
|
else if (_autoScrolling)
|
||||||
{
|
{
|
||||||
processBounceBack(dt);
|
processAutoScrolling(dt);
|
||||||
}
|
|
||||||
recordSlidTime(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScrollView::recordSlidTime(float dt)
|
|
||||||
{
|
|
||||||
if (_bePressed)
|
|
||||||
{
|
|
||||||
_slidTime += dt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,7 +892,6 @@ void ScrollView::interceptTouchEvent(Widget::TouchEventType event, Widget *sende
|
||||||
|
|
||||||
void ScrollView::processScrollEvent(MoveDirection dir, bool bounce)
|
void ScrollView::processScrollEvent(MoveDirection dir, bool bounce)
|
||||||
{
|
{
|
||||||
CCLOG("processScrollEvent() %d", dir);
|
|
||||||
ScrollviewEventType scrollEventType;
|
ScrollviewEventType scrollEventType;
|
||||||
EventType eventType;
|
EventType eventType;
|
||||||
switch(dir) {
|
switch(dir) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ THE SOFTWARE.
|
||||||
|
|
||||||
#include "ui/UILayout.h"
|
#include "ui/UILayout.h"
|
||||||
#include "ui/GUIExport.h"
|
#include "ui/GUIExport.h"
|
||||||
|
#include <list>
|
||||||
|
|
||||||
NS_CC_BEGIN
|
NS_CC_BEGIN
|
||||||
/**
|
/**
|
||||||
|
@ -430,18 +431,18 @@ protected:
|
||||||
bool isOutOfBoundaryLeftOrRight() const;
|
bool isOutOfBoundaryLeftOrRight() const;
|
||||||
|
|
||||||
void moveChildren(float offsetX, float offsetY);
|
void moveChildren(float offsetX, float offsetY);
|
||||||
void autoScrollChildren(float dt);
|
|
||||||
void startAutoScrollChildrenWithOriginalSpeed(const Vec2& dir, float v, bool attenuated, float acceleration);
|
void startInertiaScroll();
|
||||||
|
void processInertiaScrolling(float dt);
|
||||||
|
|
||||||
|
void startAutoScroll(const Vec2& deltaMove, float duration, bool attenuated);
|
||||||
void startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated);
|
void startAutoScrollChildrenWithDestination(const Vec2& des, float second, bool attenuated);
|
||||||
void jumpToDestination(const Vec2& des);
|
void processAutoScrolling(float deltaTime);
|
||||||
void stopAutoScrollChildren();
|
|
||||||
|
|
||||||
bool startBounceBackIfNeeded();
|
bool startBounceBackIfNeeded();
|
||||||
void processBounceBack(float deltaTime);
|
|
||||||
|
|
||||||
bool checkCustomScrollDestinationLeft(float* touchOffsetX, float* touchOffsetY);
|
void jumpToDestination(const Vec2& des);
|
||||||
bool checkCustomScrollDestinationRight(float* touchOffsetX, float* touchOffsetY);
|
|
||||||
bool checkCustomScrollDestination(float* touchOffsetX, float* touchOffsetY);
|
|
||||||
|
|
||||||
virtual bool scrollChildren(float touchOffsetX, float touchOffsetY);
|
virtual bool scrollChildren(float touchOffsetX, float touchOffsetY);
|
||||||
|
|
||||||
|
@ -461,8 +462,6 @@ protected:
|
||||||
|
|
||||||
virtual void interceptTouchEvent(Widget::TouchEventType event,Widget* sender,Touch *touch) override;
|
virtual void interceptTouchEvent(Widget::TouchEventType event,Widget* sender,Touch *touch) override;
|
||||||
|
|
||||||
void recordSlidTime(float dt);
|
|
||||||
|
|
||||||
void processScrollEvent(MoveDirection dir, bool bounce);
|
void processScrollEvent(MoveDirection dir, bool bounce);
|
||||||
void processScrollingEvent();
|
void processScrollingEvent();
|
||||||
void dispatchEvent(ScrollviewEventType scrollEventType, EventType eventType);
|
void dispatchEvent(ScrollviewEventType scrollEventType, EventType eventType);
|
||||||
|
@ -473,35 +472,33 @@ protected:
|
||||||
Layout* _innerContainer;
|
Layout* _innerContainer;
|
||||||
|
|
||||||
Direction _direction;
|
Direction _direction;
|
||||||
Vec2 _autoScrollDir;
|
|
||||||
|
|
||||||
float _topBoundary;
|
float _topBoundary;
|
||||||
float _bottomBoundary;
|
float _bottomBoundary;
|
||||||
float _leftBoundary;
|
float _leftBoundary;
|
||||||
float _rightBoundary;
|
float _rightBoundary;
|
||||||
|
|
||||||
bool _autoScroll;
|
|
||||||
float _autoScrollAddUpTime;
|
|
||||||
|
|
||||||
float _autoScrollOriginalSpeed;
|
|
||||||
float _autoScrollAcceleration;
|
|
||||||
bool _isAutoScrollSpeedAttenuated;
|
|
||||||
bool _needCheckAutoScrollDestination;
|
|
||||||
Vec2 _autoScrollDestination;
|
|
||||||
|
|
||||||
bool _bePressed;
|
bool _bePressed;
|
||||||
float _slidTime;
|
|
||||||
float _childFocusCancelOffset;
|
float _childFocusCancelOffset;
|
||||||
|
|
||||||
|
bool _inertiaScrollEnabled;
|
||||||
|
bool _inertiaScrolling;
|
||||||
|
Vec2 _inertiaInitiVelocity;
|
||||||
|
std::list<Vec2> _inertiaTouchDisplacements;
|
||||||
|
std::list<float> _inertiaTouchTimeDeltas;
|
||||||
|
long long _inertiaPrevTouchTimestamp;
|
||||||
|
float _inertiaScrollExpectedTime;
|
||||||
|
float _inertiaScrollElapsedTime;
|
||||||
|
|
||||||
|
bool _autoScrolling;
|
||||||
|
bool _autoScrollAttenuate;
|
||||||
|
Vec2 _autoScrollStartPosition;
|
||||||
|
Vec2 _autoScrollTargetDelta;
|
||||||
|
float _autoScrollDuration;
|
||||||
|
float _autoScrollAccumulatedTime;
|
||||||
|
|
||||||
bool _bounceEnabled;
|
bool _bounceEnabled;
|
||||||
bool _bouncingBack;
|
bool _bouncingBack;
|
||||||
bool _bounceBackAttenuate;
|
|
||||||
Vec2 _bounceBackStartPosition;
|
|
||||||
Vec2 _bounceBackTargetDelta;
|
|
||||||
float _bounceBackDuration;
|
|
||||||
float _bounceBackAccumulatedTime;
|
|
||||||
|
|
||||||
bool _inertiaScrollEnabled;
|
|
||||||
|
|
||||||
Ref* _scrollViewEventListener;
|
Ref* _scrollViewEventListener;
|
||||||
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
|
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
|
||||||
|
|
Loading…
Reference in New Issue