@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!isEnabled()) return false;
int action = ev.getActionMasked();
int pointerIndex;
switch (action) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
isBeingDragged = false;
pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex < 0) {
return false;
}
mLastMotionX = ev.getX(pointerIndex);
mLastMotionY = ev.getY(pointerIndex);
break;
case MotionEvent.ACTION_MOVE:
if (mActivePointerId == MotionEvent.INVALID_POINTER_ID) {
return false;
}
pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex < 0) {
return false;
}
startDragging(ev.getX(pointerIndex), ev.getY(pointerIndex));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isBeingDragged = false;
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
break;
}
return isBeingDragged;
}
public boolean onTouchEvent(MotionEvent ev) {
if (!isEnabled()) return false;
int action = ev.getActionMasked();
int pointerIndex;
switch (action) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
isBeingDragged = false;
break;
case MotionEvent.ACTION_MOVE: {
pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex < 0) {
return false;
}
startDragging(ev.getX(pointerIndex), ev.getY(pointerIndex));
float x = ev.getX(pointerIndex);
float y = ev.getY(pointerIndex);
float value = mOrientation == HORIZONTAL ? x : y;
float lastValue = mOrientation == HORIZONTAL ? mLastMotionX : mLastMotionY;
if (isBeingDragged) {
int offset = (int) ((value - lastValue) / DRAGGING_RESISTANCE);
if (mDirection == DIRECTION_POSITIVE && mContentOffset + offset < 0 ||
mDirection == DIRECTION_NEGATIVE && mContentOffset + offset > 0) {
offset = -mContentOffset;
}
offsetChildren(offset);
mLastMotionX = x;
mLastMotionY = y;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (isBeingDragged) {
isBeingDragged = false;
animateOffsetToZero();
}
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
return false;
case MotionEvent.ACTION_POINTER_DOWN: {
pointerIndex = ev.getActionIndex();
if (pointerIndex < 0) {
return false;
}
mActivePointerId = ev.getPointerId(pointerIndex);
mLastMotionX = ev.getX(pointerIndex);
mLastMotionY = ev.getY(pointerIndex);
break;
}
case MotionEvent.ACTION_POINTER_UP:
pointerIndex = ev.getActionIndex();
int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastMotionX = ev.getX(newPointerIndex);
mLastMotionY = ev.getY(newPointerIndex);
}
break;
}
return true;
}
private boolean canScroll(View view, float x, float y, int direction) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
int scrollX = viewGroup.getScrollX();
int scrollY = viewGroup.getScrollY();
int count = viewGroup.getChildCount();
for (int i = count - 1; i >= 0; --i) {
View child = viewGroup.getChildAt(i);
if (x + scrollX >= child.getLeft() &&
x + scrollX < child.getRight() &&
y + scrollY >= child.getTop() &&
y + scrollY < child.getBottom() &&
canScroll(child, x + scrollX - child.getLeft(), y + scrollY - child.getTop(), direction)) {
return true;
}
}
}
return mOrientation == HORIZONTAL ? view.canScrollHorizontally(direction) : view.canScrollVertically(direction);
}
private void startDragging(float x, float y) {
if (isBeingDragged) return;
if (mOrientation == HORIZONTAL) {
startDraggingHorizontal(x, y);
} else {
startDraggingVertical(x, y);
}
}
private void startDraggingHorizontal(float x, float y) {
float diffX = x - mLastMotionX;
float diffY = y - mLastMotionY;
if (Math.abs(diffX) < Math.abs(diffY)) return;
if (diffX > mTouchSlop && !canScroll(mContent, x, y, DIRECTION_NEGATIVE) ||
diffX < -mTouchSlop && !canScroll(mContent, x, y, DIRECTION_POSITIVE)) {
mLastMotionX = mLastMotionX + (diffX > 0 ? mTouchSlop : -mTouchSlop);
mDirection = diffX > 0 ? DIRECTION_POSITIVE : DIRECTION_NEGATIVE;
isBeingDragged = true;
requestDisallowInterceptTouchEvent(true);
}
}
private void startDraggingVertical(float x, float y) {
float diffX = x - mLastMotionX;
float diffY = y - mLastMotionY;
if (Math.abs(diffX) > Math.abs(diffY)) return;
if (diffY > mTouchSlop && !canScroll(mContent, x, y, DIRECTION_NEGATIVE) ||
diffY < -mTouchSlop && !canScroll(mContent, x, y, DIRECTION_POSITIVE)) {
mLastMotionY = mLastMotionY + (diffY > 0 ? mTouchSlop : -mTouchSlop);
mDirection = diffY > 0 ? DIRECTION_POSITIVE : DIRECTION_NEGATIVE;
isBeingDragged = true;
requestDisallowInterceptTouchEvent(true);
}
}
private void offsetChildren(int offset) {
if (offset == 0) return;
if (mOrientation == HORIZONTAL) {
offsetHorizontal(offset);
} else {
offsetVertical(offset);
}
}
private void offsetHorizontal(int offset) {
if (mHeader != null) {
int displayMode = ((LayoutParams) mHeader.getLayoutParams()).getDisplayMode();
if (displayMode == LayoutParams.DISPLAY_MODE_EDGE && mHeader.getLeft() <= 0) {
if (mHeader.getLeft() + offset <= 0) {
mHeaderOffset += offset;
ViewCompat.offsetLeftAndRight(mHeader, offset);
} else {
mHeaderOffset = 0;
ViewCompat.offsetLeftAndRight(mHeader, 0 - mHeader.getLeft());
}
} else if (displayMode == LayoutParams.DISPLAY_MODE_SCROLL) {
mHeaderOffset += offset;
ViewCompat.offsetLeftAndRight(mHeader, offset);
}
}
if (mContent != null) {
mContentOffset += offset;
ViewCompat.offsetLeftAndRight(mContent, offset);
}
if (mFooter != null) {
int displayMode = ((LayoutParams) mFooter.getLayoutParams()).getDisplayMode();
if (displayMode == LayoutParams.DISPLAY_MODE_EDGE && mFooter.getRight() >= getMeasuredWidth()) {
if (mFooter.getRight() + offset >= getMeasuredWidth()) {
mFooterOffset += offset;
ViewCompat.offsetLeftAndRight(mFooter, offset);
} else {
mFooterOffset = 0;
ViewCompat.offsetLeftAndRight(mFooter, getMeasuredWidth() - mFooter.getRight());
}
} else if (displayMode == LayoutParams.DISPLAY_MODE_SCROLL) {
mFooterOffset += offset;
ViewCompat.offsetLeftAndRight(mFooter, offset);
}
}
}
private void offsetVertical(int offset) {
if (mHeader != null) {
int displayMode = ((LayoutParams) mHeader.getLayoutParams()).getDisplayMode();
if (displayMode == LayoutParams.DISPLAY_MODE_EDGE && mHeader.getTop() <= 0) {
if (mHeader.getTop() + offset <= 0) {
mHeaderOffset += offset;
ViewCompat.offsetTopAndBottom(mHeader, offset);
} else {
mHeaderOffset = 0;
ViewCompat.offsetTopAndBottom(mHeader, 0 - mHeader.getTop());
}
} else if (displayMode == LayoutParams.DISPLAY_MODE_SCROLL) {
mHeaderOffset += offset;
ViewCompat.offsetTopAndBottom(mHeader, offset);
}
}
if (mContent != null) {
mContentOffset += offset;
ViewCompat.offsetTopAndBottom(mContent, offset);
}
if (mFooter != null) {
int displayMode = ((LayoutParams) mFooter.getLayoutParams()).getDisplayMode();
if (displayMode == LayoutParams.DISPLAY_MODE_EDGE && mFooter.getBottom() >= getMeasuredHeight()) {
if (mFooter.getBottom() + offset >= getMeasuredHeight()) {
mFooterOffset += offset;
ViewCompat.offsetTopAndBottom(mFooter, offset);
} else {
mFooterOffset = 0;
ViewCompat.offsetTopAndBottom(mFooter, getMeasuredHeight() - mFooter.getBottom());
}
} else if (displayMode == LayoutParams.DISPLAY_MODE_SCROLL) {
mFooterOffset += offset;
ViewCompat.offsetTopAndBottom(mFooter, offset);
}
}
}