Merge branch 'feature/elastic_inertia_scroll' into feature/elastic_scrollview

Apply elastic movement to inertia scroll
This commit is contained in:
Neo Kim 2015-06-22 14:50:12 +09:00
commit ff5dbd5a52
2 changed files with 167 additions and 364 deletions

View File

@ -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) {

View File

@ -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)))