Merge "Handle DOWN/MOVE/UP gestures with fling. Bug: 5265814"
This commit is contained in:
@@ -2771,15 +2771,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean startScrollIfNeeded(int deltaY) {
|
private boolean startScrollIfNeeded(int y) {
|
||||||
// Check if we have moved far enough that it looks more like a
|
// Check if we have moved far enough that it looks more like a
|
||||||
// scroll than a tap
|
// scroll than a tap
|
||||||
|
final int deltaY = y - mMotionY;
|
||||||
final int distance = Math.abs(deltaY);
|
final int distance = Math.abs(deltaY);
|
||||||
final boolean overscroll = mScrollY != 0;
|
final boolean overscroll = mScrollY != 0;
|
||||||
if (overscroll || distance > mTouchSlop) {
|
if (overscroll || distance > mTouchSlop) {
|
||||||
createScrollingCache();
|
createScrollingCache();
|
||||||
mTouchMode = overscroll ? TOUCH_MODE_OVERSCROLL : TOUCH_MODE_SCROLL;
|
if (overscroll) {
|
||||||
mMotionCorrection = deltaY;
|
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
||||||
|
mMotionCorrection = 0;
|
||||||
|
} else {
|
||||||
|
mTouchMode = TOUCH_MODE_SCROLL;
|
||||||
|
mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
|
||||||
|
}
|
||||||
final Handler handler = getHandler();
|
final Handler handler = getHandler();
|
||||||
// Handler should not be null unless the AbsListView is not attached to a
|
// Handler should not be null unless the AbsListView is not attached to a
|
||||||
// window, which would make it very hard to scroll it... but the monkeys
|
// window, which would make it very hard to scroll it... but the monkeys
|
||||||
@@ -2799,12 +2805,176 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
parent.requestDisallowInterceptTouchEvent(true);
|
parent.requestDisallowInterceptTouchEvent(true);
|
||||||
}
|
}
|
||||||
|
scrollIfNeeded(y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scrollIfNeeded(int y) {
|
||||||
|
final int rawDeltaY = y - mMotionY;
|
||||||
|
final int deltaY = rawDeltaY - mMotionCorrection;
|
||||||
|
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
|
||||||
|
|
||||||
|
if (mTouchMode == TOUCH_MODE_SCROLL) {
|
||||||
|
if (PROFILE_SCROLLING) {
|
||||||
|
if (!mScrollProfilingStarted) {
|
||||||
|
Debug.startMethodTracing("AbsListViewScroll");
|
||||||
|
mScrollProfilingStarted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mScrollStrictSpan == null) {
|
||||||
|
// If it's non-null, we're already in a scroll.
|
||||||
|
mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y != mLastY) {
|
||||||
|
// We may be here after stopping a fling and continuing to scroll.
|
||||||
|
// If so, we haven't disallowed intercepting touch events yet.
|
||||||
|
// Make sure that we do so in case we're in a parent that can intercept.
|
||||||
|
if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
|
||||||
|
Math.abs(rawDeltaY) > mTouchSlop) {
|
||||||
|
final ViewParent parent = getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.requestDisallowInterceptTouchEvent(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int motionIndex;
|
||||||
|
if (mMotionPosition >= 0) {
|
||||||
|
motionIndex = mMotionPosition - mFirstPosition;
|
||||||
|
} else {
|
||||||
|
// If we don't have a motion position that we can reliably track,
|
||||||
|
// pick something in the middle to make a best guess at things below.
|
||||||
|
motionIndex = getChildCount() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int motionViewPrevTop = 0;
|
||||||
|
View motionView = this.getChildAt(motionIndex);
|
||||||
|
if (motionView != null) {
|
||||||
|
motionViewPrevTop = motionView.getTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to do all this work if we're not going to move anyway
|
||||||
|
boolean atEdge = false;
|
||||||
|
if (incrementalDeltaY != 0) {
|
||||||
|
atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if we have bumped into the scroll limit
|
||||||
|
motionView = this.getChildAt(motionIndex);
|
||||||
|
if (motionView != null) {
|
||||||
|
// Check if the top of the motion view is where it is
|
||||||
|
// supposed to be
|
||||||
|
final int motionViewRealTop = motionView.getTop();
|
||||||
|
if (atEdge) {
|
||||||
|
// Apply overscroll
|
||||||
|
|
||||||
|
int overscroll = -incrementalDeltaY -
|
||||||
|
(motionViewRealTop - motionViewPrevTop);
|
||||||
|
overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
|
||||||
|
0, mOverscrollDistance, true);
|
||||||
|
if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
|
||||||
|
// Don't allow overfling if we're at the edge.
|
||||||
|
if (mVelocityTracker != null) {
|
||||||
|
mVelocityTracker.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int overscrollMode = getOverScrollMode();
|
||||||
|
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||||
|
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||||
|
!contentFits())) {
|
||||||
|
mDirection = 0; // Reset when entering overscroll.
|
||||||
|
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
||||||
|
if (rawDeltaY > 0) {
|
||||||
|
mEdgeGlowTop.onPull((float) overscroll / getHeight());
|
||||||
|
if (!mEdgeGlowBottom.isFinished()) {
|
||||||
|
mEdgeGlowBottom.onRelease();
|
||||||
|
}
|
||||||
|
} else if (rawDeltaY < 0) {
|
||||||
|
mEdgeGlowBottom.onPull((float) overscroll / getHeight());
|
||||||
|
if (!mEdgeGlowTop.isFinished()) {
|
||||||
|
mEdgeGlowTop.onRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mMotionY = y;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
mLastY = y;
|
||||||
|
}
|
||||||
|
} else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
|
||||||
|
if (y != mLastY) {
|
||||||
|
final int oldScroll = mScrollY;
|
||||||
|
final int newScroll = oldScroll - incrementalDeltaY;
|
||||||
|
int newDirection = y > mLastY ? 1 : -1;
|
||||||
|
|
||||||
|
if (mDirection == 0) {
|
||||||
|
mDirection = newDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
int overScrollDistance = -incrementalDeltaY;
|
||||||
|
if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
|
||||||
|
overScrollDistance = -oldScroll;
|
||||||
|
incrementalDeltaY += overScrollDistance;
|
||||||
|
} else {
|
||||||
|
incrementalDeltaY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overScrollDistance != 0) {
|
||||||
|
overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
|
||||||
|
0, mOverscrollDistance, true);
|
||||||
|
final int overscrollMode = getOverScrollMode();
|
||||||
|
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
||||||
|
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
||||||
|
!contentFits())) {
|
||||||
|
if (rawDeltaY > 0) {
|
||||||
|
mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
|
||||||
|
if (!mEdgeGlowBottom.isFinished()) {
|
||||||
|
mEdgeGlowBottom.onRelease();
|
||||||
|
}
|
||||||
|
} else if (rawDeltaY < 0) {
|
||||||
|
mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
|
||||||
|
if (!mEdgeGlowTop.isFinished()) {
|
||||||
|
mEdgeGlowTop.onRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incrementalDeltaY != 0) {
|
||||||
|
// Coming back to 'real' list scrolling
|
||||||
|
mScrollY = 0;
|
||||||
|
invalidateParentIfNeeded();
|
||||||
|
|
||||||
|
// No need to do all this work if we're not going to move anyway
|
||||||
|
if (incrementalDeltaY != 0) {
|
||||||
|
trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTouchMode = TOUCH_MODE_SCROLL;
|
||||||
|
|
||||||
|
// We did not scroll the full amount. Treat this essentially like the
|
||||||
|
// start of a new touch scroll
|
||||||
|
final int motionPosition = findClosestMotionRow(y);
|
||||||
|
|
||||||
|
mMotionCorrection = 0;
|
||||||
|
View motionView = getChildAt(motionPosition - mFirstPosition);
|
||||||
|
mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
|
||||||
|
mMotionY = y;
|
||||||
|
mMotionPosition = motionPosition;
|
||||||
|
}
|
||||||
|
mLastY = y;
|
||||||
|
mDirection = newDirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void onTouchModeChanged(boolean isInTouchMode) {
|
public void onTouchModeChanged(boolean isInTouchMode) {
|
||||||
if (isInTouchMode) {
|
if (isInTouchMode) {
|
||||||
// Get rid of the selection when we enter touch mode
|
// Get rid of the selection when we enter touch mode
|
||||||
@@ -2856,7 +3026,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
final int action = ev.getAction();
|
final int action = ev.getAction();
|
||||||
|
|
||||||
View v;
|
View v;
|
||||||
int deltaY;
|
|
||||||
|
|
||||||
initVelocityTrackerIfNotExists();
|
initVelocityTrackerIfNotExists();
|
||||||
mVelocityTracker.addMovement(ev);
|
mVelocityTracker.addMovement(ev);
|
||||||
@@ -2935,183 +3104,19 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
mActivePointerId = ev.getPointerId(pointerIndex);
|
mActivePointerId = ev.getPointerId(pointerIndex);
|
||||||
}
|
}
|
||||||
final int y = (int) ev.getY(pointerIndex);
|
final int y = (int) ev.getY(pointerIndex);
|
||||||
deltaY = y - mMotionY;
|
|
||||||
switch (mTouchMode) {
|
switch (mTouchMode) {
|
||||||
case TOUCH_MODE_DOWN:
|
case TOUCH_MODE_DOWN:
|
||||||
case TOUCH_MODE_TAP:
|
case TOUCH_MODE_TAP:
|
||||||
case TOUCH_MODE_DONE_WAITING:
|
case TOUCH_MODE_DONE_WAITING:
|
||||||
// Check if we have moved far enough that it looks more like a
|
// Check if we have moved far enough that it looks more like a
|
||||||
// scroll than a tap
|
// scroll than a tap
|
||||||
startScrollIfNeeded(deltaY);
|
startScrollIfNeeded(y);
|
||||||
break;
|
break;
|
||||||
case TOUCH_MODE_SCROLL:
|
case TOUCH_MODE_SCROLL:
|
||||||
if (PROFILE_SCROLLING) {
|
|
||||||
if (!mScrollProfilingStarted) {
|
|
||||||
Debug.startMethodTracing("AbsListViewScroll");
|
|
||||||
mScrollProfilingStarted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mScrollStrictSpan == null) {
|
|
||||||
// If it's non-null, we're already in a scroll.
|
|
||||||
mScrollStrictSpan = StrictMode.enterCriticalSpan("AbsListView-scroll");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y != mLastY) {
|
|
||||||
// We may be here after stopping a fling and continuing to scroll.
|
|
||||||
// If so, we haven't disallowed intercepting touch events yet.
|
|
||||||
// Make sure that we do so in case we're in a parent that can intercept.
|
|
||||||
if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
|
|
||||||
Math.abs(deltaY) > mTouchSlop) {
|
|
||||||
final ViewParent parent = getParent();
|
|
||||||
if (parent != null) {
|
|
||||||
parent.requestDisallowInterceptTouchEvent(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final int rawDeltaY = deltaY;
|
|
||||||
deltaY -= mMotionCorrection;
|
|
||||||
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
|
|
||||||
|
|
||||||
final int motionIndex;
|
|
||||||
if (mMotionPosition >= 0) {
|
|
||||||
motionIndex = mMotionPosition - mFirstPosition;
|
|
||||||
} else {
|
|
||||||
// If we don't have a motion position that we can reliably track,
|
|
||||||
// pick something in the middle to make a best guess at things below.
|
|
||||||
motionIndex = getChildCount() / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int motionViewPrevTop = 0;
|
|
||||||
View motionView = this.getChildAt(motionIndex);
|
|
||||||
if (motionView != null) {
|
|
||||||
motionViewPrevTop = motionView.getTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to do all this work if we're not going to move anyway
|
|
||||||
boolean atEdge = false;
|
|
||||||
if (incrementalDeltaY != 0) {
|
|
||||||
atEdge = trackMotionScroll(deltaY, incrementalDeltaY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if we have bumped into the scroll limit
|
|
||||||
motionView = this.getChildAt(motionIndex);
|
|
||||||
if (motionView != null) {
|
|
||||||
// Check if the top of the motion view is where it is
|
|
||||||
// supposed to be
|
|
||||||
final int motionViewRealTop = motionView.getTop();
|
|
||||||
if (atEdge) {
|
|
||||||
// Apply overscroll
|
|
||||||
|
|
||||||
int overscroll = -incrementalDeltaY -
|
|
||||||
(motionViewRealTop - motionViewPrevTop);
|
|
||||||
overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
|
|
||||||
0, mOverscrollDistance, true);
|
|
||||||
if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
|
|
||||||
// Don't allow overfling if we're at the edge.
|
|
||||||
if (mVelocityTracker != null) {
|
|
||||||
mVelocityTracker.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final int overscrollMode = getOverScrollMode();
|
|
||||||
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
|
||||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
|
||||||
!contentFits())) {
|
|
||||||
mDirection = 0; // Reset when entering overscroll.
|
|
||||||
mTouchMode = TOUCH_MODE_OVERSCROLL;
|
|
||||||
if (rawDeltaY > 0) {
|
|
||||||
mEdgeGlowTop.onPull((float) overscroll / getHeight());
|
|
||||||
if (!mEdgeGlowBottom.isFinished()) {
|
|
||||||
mEdgeGlowBottom.onRelease();
|
|
||||||
}
|
|
||||||
} else if (rawDeltaY < 0) {
|
|
||||||
mEdgeGlowBottom.onPull((float) overscroll / getHeight());
|
|
||||||
if (!mEdgeGlowTop.isFinished()) {
|
|
||||||
mEdgeGlowTop.onRelease();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mMotionY = y;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
mLastY = y;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOUCH_MODE_OVERSCROLL:
|
case TOUCH_MODE_OVERSCROLL:
|
||||||
if (y != mLastY) {
|
scrollIfNeeded(y);
|
||||||
final int rawDeltaY = deltaY;
|
|
||||||
deltaY -= mMotionCorrection;
|
|
||||||
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
|
|
||||||
|
|
||||||
final int oldScroll = mScrollY;
|
|
||||||
final int newScroll = oldScroll - incrementalDeltaY;
|
|
||||||
int newDirection = y > mLastY ? 1 : -1;
|
|
||||||
|
|
||||||
if (mDirection == 0) {
|
|
||||||
mDirection = newDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
int overScrollDistance = -incrementalDeltaY;
|
|
||||||
if ((newScroll < 0 && oldScroll >= 0) || (newScroll > 0 && oldScroll <= 0)) {
|
|
||||||
overScrollDistance = -oldScroll;
|
|
||||||
incrementalDeltaY += overScrollDistance;
|
|
||||||
} else {
|
|
||||||
incrementalDeltaY = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overScrollDistance != 0) {
|
|
||||||
overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,
|
|
||||||
0, mOverscrollDistance, true);
|
|
||||||
final int overscrollMode = getOverScrollMode();
|
|
||||||
if (overscrollMode == OVER_SCROLL_ALWAYS ||
|
|
||||||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
|
|
||||||
!contentFits())) {
|
|
||||||
if (rawDeltaY > 0) {
|
|
||||||
mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
|
|
||||||
if (!mEdgeGlowBottom.isFinished()) {
|
|
||||||
mEdgeGlowBottom.onRelease();
|
|
||||||
}
|
|
||||||
} else if (rawDeltaY < 0) {
|
|
||||||
mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
|
|
||||||
if (!mEdgeGlowTop.isFinished()) {
|
|
||||||
mEdgeGlowTop.onRelease();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (incrementalDeltaY != 0) {
|
|
||||||
// Coming back to 'real' list scrolling
|
|
||||||
mScrollY = 0;
|
|
||||||
invalidateParentIfNeeded();
|
|
||||||
|
|
||||||
// No need to do all this work if we're not going to move anyway
|
|
||||||
if (incrementalDeltaY != 0) {
|
|
||||||
trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
|
|
||||||
}
|
|
||||||
|
|
||||||
mTouchMode = TOUCH_MODE_SCROLL;
|
|
||||||
|
|
||||||
// We did not scroll the full amount. Treat this essentially like the
|
|
||||||
// start of a new touch scroll
|
|
||||||
final int motionPosition = findClosestMotionRow(y);
|
|
||||||
|
|
||||||
mMotionCorrection = 0;
|
|
||||||
View motionView = getChildAt(motionPosition - mFirstPosition);
|
|
||||||
mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
|
|
||||||
mMotionY = y;
|
|
||||||
mMotionPosition = motionPosition;
|
|
||||||
}
|
|
||||||
mLastY = y;
|
|
||||||
mDirection = newDirection;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3542,7 +3547,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
final int y = (int) ev.getY(pointerIndex);
|
final int y = (int) ev.getY(pointerIndex);
|
||||||
initVelocityTrackerIfNotExists();
|
initVelocityTrackerIfNotExists();
|
||||||
mVelocityTracker.addMovement(ev);
|
mVelocityTracker.addMovement(ev);
|
||||||
if (startScrollIfNeeded(y - mMotionY)) {
|
if (startScrollIfNeeded(y)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user