Fix some bugs/edge cases in ScrollView/HorizontalScrollView

Handle ACTION_CANCEL, fix edge cases related to grabbing content and
beginning a new scroll during overfling/springback. Will prevent
some cases where a view could get stuck overscrolled.

Change-Id: I7e89d9de9b7dc685d2ea278e6b2bd2c794364204
This commit is contained in:
Adam Powell
2010-03-24 14:23:43 -07:00
parent 3e8b72ac6e
commit 352b978fa8
2 changed files with 55 additions and 20 deletions

View File

@@ -372,11 +372,12 @@ public class HorizontalScrollView extends FrameLayout {
private boolean inChild(int x, int y) {
if (getChildCount() > 0) {
final int scrollX = mScrollX;
final View child = getChildAt(0);
return !(y < child.getTop()
|| y >= child.getBottom()
|| x < child.getLeft()
|| x >= child.getRight());
|| x < child.getLeft() - scrollX
|| x >= child.getRight() - scrollX);
}
return false;
}
@@ -455,6 +456,9 @@ public class HorizontalScrollView extends FrameLayout {
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
if (mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
invalidate();
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
@@ -486,21 +490,22 @@ public class HorizontalScrollView extends FrameLayout {
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
final float x = ev.getX();
if (!(mIsBeingDragged = inChild((int) x, (int) ev.getY()))) {
return false;
}
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
mLastMotionX = x;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE:
@@ -544,6 +549,19 @@ public class HorizontalScrollView extends FrameLayout {
}
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
if (mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
invalidate();
}
mActivePointerId = INVALID_POINTER;
mIsBeingDragged = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;

View File

@@ -370,9 +370,10 @@ public class ScrollView extends FrameLayout {
private boolean inChild(int x, int y) {
if (getChildCount() > 0) {
final int scrollY = mScrollY;
final View child = getChildAt(0);
return !(y < child.getTop()
|| y >= child.getBottom()
return !(y < child.getTop() - scrollY
|| y >= child.getBottom() - scrollY
|| x < child.getLeft()
|| x >= child.getRight());
}
@@ -452,6 +453,9 @@ public class ScrollView extends FrameLayout {
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
invalidate();
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
@@ -483,19 +487,19 @@ public class ScrollView extends FrameLayout {
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
final float y = ev.getY();
if (!(mIsBeingDragged = inChild((int) ev.getX(), (int) y))) {
return false;
}
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
mLastMotionY = y;
mActivePointerId = ev.getPointerId(0);
@@ -542,6 +546,19 @@ public class ScrollView extends FrameLayout {
}
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
invalidate();
}
mActivePointerId = INVALID_POINTER;
mIsBeingDragged = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;