@Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // This is called at drawing time by ViewGroup. We don't want to // re-show the scrollbars at this point, which scrollTo will do, // so we replicate most of scrollTo here. // // It's a little odd to call onScrollChanged from inside the drawing. // // It is, except when you remember that computeScroll() is used to // animate scrolling. So unless we want to defer the onScrollChanged() // until the end of the animated scrolling, we don't really have a // choice here. // // I agree. The alternative, which I think would be worse, is to post // something and tell the subclasses later. This is bad because there // will be a window where mScrollX/Y is different from what the app // thinks it is. // int oldX = getScrollX(); int oldY = getScrollY(); int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (oldX != x || oldY != y) { final int range = getScrollRange(); final int overscrollMode = getOverScrollMode(); final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); overScrollBy(x - oldX, y - oldY, oldX, oldY, range, 0, mOverflingDistance, 0, false); onScrollChanged(getScrollX(), getScrollY(), oldX, oldY); } if (!awakenScrollBars()) { postInvalidateOnAnimation(); } } else { int scrollX = getScrollX(); int finalX = getScrollXFromFinalX(scrollX); if (!mIsBeingDragged && scrollX != finalX) { if (mScroller.springBack(getScrollX(), getScrollY(), finalX, finalX, 0, 0)) { postInvalidateOnAnimation(); } } } }
private boolean touchEvent(MotionEvent ev) { initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); final int action = ev.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { if (getChildCount() == 0 || !inScrollArea(ev)) { return false; } if ((mIsBeingDragged = !mScroller.isFinished())) { final ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } } /* * 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 = (int) ev.getX(); mActivePointerId = ev.getPointerId(0); break; } case MotionEvent.ACTION_MOVE: final int activePointerIndex = ev.findPointerIndex(mActivePointerId); if (activePointerIndex == -1) { Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent"); break; } final int x = (int) ev.getX(activePointerIndex); int deltaX = mLastMotionX - x; if (!mIsBeingDragged && Math.abs(deltaX) > mTouchSlop) { final ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } mIsBeingDragged = true; if (deltaX > 0) { deltaX -= mTouchSlop; } else { deltaX += mTouchSlop; } } if (mIsBeingDragged) { // Scroll to follow the motion event mLastMotionX = x; final int oldX = getScrollX(); final int oldY = getScrollY(); final int range = getScrollRange(); final int overscrollMode = getOverScrollMode(); final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); if (overScrollBy(deltaX, 0, getScrollX(), 0, range, 0, mOverscrollDistance, 0, true)) { // Break our velocity if we hit a scroll barrier. mVelocityTracker.clear(); } onScrollChanged(getScrollX(), getScrollY(), oldX, oldY); } break; case MotionEvent.ACTION_UP: if (mIsBeingDragged) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId); if (getChildCount() > 0) { if ((Math.abs(initialVelocity) > mMinimumVelocity)) { fling(-initialVelocity); } else { int finalX = getScrollX(); finalX = getScrollXFromFinalX(finalX); if (mScroller.springBack(getScrollX(), getScrollY(), finalX, finalX, 0, 0)) { postInvalidateOnAnimation(); } } } mActivePointerId = INVALID_POINTER; mIsBeingDragged = false; recycleVelocityTracker(); } break; case MotionEvent.ACTION_CANCEL: if (mIsBeingDragged && getChildCount() > 0) { if (mScroller.springBack(getScrollX(), getScrollY(), 0, getScrollRange(), 0, 0)) { postInvalidateOnAnimation(); } mActivePointerId = INVALID_POINTER; mIsBeingDragged = false; recycleVelocityTracker(); } break; case MotionEvent.ACTION_POINTER_UP: onSecondaryPointerUp(ev); break; } return true; }
@Override public boolean onTouchEvent(MotionEvent event) { // return super.onTouchEvent(event); // int height = getHeight(); initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(event); int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { if (!mIsDown) { mIsDown = true; mDownPt.x = event.getX(); mDownPt.y = event.getY(); mDownedScrollPt.x = getScrollX(); mDownedScrollPt.y = getScrollY(); // initOrResetVelocityTracker(); // mVelocityTracker.addMovement(event); if (!mScroller.isFinished()) { mScroller.abortAnimation(); } } } else if (action == MotionEvent.ACTION_MOVE) { if (mIsDown) { float x = event.getX(); float y = event.getY(); float sx = -(x - mDownPt.x) + mDownedScrollPt.x; float sy = -(y - mDownPt.y) + mDownedScrollPt.y; scrollTo((int) sx, (int) sy); // initVelocityTrackerIfNotExists(); // mVelocityTracker.addMovement(event); } } else if (action == MotionEvent.ACTION_UP) { if (mIsDown) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getYVelocity(event.getPointerId(0)); int initialVelocitx = (int) velocityTracker.getXVelocity(event.getPointerId(0)); fling(-initialVelocitx, -initialVelocity); recycleVelocityTracker(); mIsDown = false; } } else if (action == MotionEvent.ACTION_CANCEL) { if (mIsDown) { if (mScroller.springBack( getScrollX(), getScrollY(), 0, getScrollRangeX(), 0, getScrollRangeY())) { // postInvalidateOnAnimation(); postInvalidate(); } recycleVelocityTracker(); mIsDown = false; } } return true; }
private boolean interceptTouchEvent(MotionEvent ev) { /* * This method JUST determines whether we want to intercept the motion. If we * return true, onMotionEvent will be called and we do the actual scrolling there. */ /* * Shortcut the most recurring case: the user is in the dragging state and he is * moving his finger. We want to intercept this motion. */ final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; } switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE: { /* * mIsBeingDragged == false, otherwise the shortcut would have caught it. * Check whether the user has moved far enough from his original down touch. */ /* * Locally do absolute value. mLastMotionX is set to the x value of the down * event. */ final int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) { // If we don't have a valid id, the touch down wasn't on content. break; } final int pointerIndex = ev.findPointerIndex(activePointerId); if (pointerIndex == -1) { Log.e(TAG, "Invalid pointerId=" + activePointerId + " in onInterceptTouchEvent"); break; } final int x = (int) ev.getX(pointerIndex); final int xDiff = (int) Math.abs(x - mLastMotionX); if (xDiff > mTouchSlop) { setHorizontalScrollBarEnabled(true); mIsBeingDragged = true; mLastMotionX = x; initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); if (getParent() != null) getParent().requestDisallowInterceptTouchEvent(true); } break; } case MotionEvent.ACTION_DOWN: { final int x = (int) ev.getX(); if (!inChild((int) x, (int) ev.getY())) { mIsBeingDragged = false; recycleVelocityTracker(); break; } /* * Remember location of down touch. ACTION_DOWN always refers to pointer index * 0. */ mLastMotionX = x; mActivePointerId = ev.getPointerId(0); initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); /* * If being flinged and user touches the screen, initiate drag; otherwise * don't. mScroller.isFinished should be false when being flinged. */ mIsBeingDragged = false; break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: /* Release the drag */ mIsBeingDragged = false; mActivePointerId = INVALID_POINTER; if (mScroller.springBack(getScrollX(), getScrollY(), 0, getScrollRange(), 0, 0)) { postInvalidateOnAnimation(); } break; case MotionEvent.ACTION_POINTER_DOWN: { final int index = ev.getActionIndex(); mLastMotionX = (int) ev.getX(index); mActivePointerId = ev.getPointerId(index); break; } case MotionEvent.ACTION_POINTER_UP: onSecondaryPointerUp(ev); mLastMotionX = (int) ev.getX(ev.findPointerIndex(mActivePointerId)); break; } /* * The only time we want to intercept motion events is if we are in the drag mode. */ return mIsBeingDragged; }
public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) { return mScroller.springBack(startX, startY, minX, maxX, minY, maxY); }