779 lines
27 KiB
Java
779 lines
27 KiB
Java
package net.simonvt.menudrawer;
|
|
|
|
import android.app.Activity;
|
|
import android.content.Context;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.drawable.GradientDrawable;
|
|
import android.util.AttributeSet;
|
|
import android.view.MotionEvent;
|
|
import android.view.VelocityTracker;
|
|
import android.view.View;
|
|
|
|
public class OverlayDrawer extends DraggableDrawer {
|
|
private int mPeekSize;
|
|
|
|
private Runnable mRevealRunnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
cancelContentTouch();
|
|
int animateTo = 0;
|
|
switch (getPosition()) {
|
|
case RIGHT:
|
|
case BOTTOM:
|
|
animateTo = -mPeekSize;
|
|
break;
|
|
|
|
default:
|
|
animateTo = mPeekSize;
|
|
break;
|
|
}
|
|
animateOffsetTo(animateTo, 250);
|
|
}
|
|
};
|
|
|
|
OverlayDrawer(Activity activity, int dragMode) {
|
|
super(activity, dragMode);
|
|
}
|
|
|
|
public OverlayDrawer(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
public OverlayDrawer(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
}
|
|
|
|
public OverlayDrawer(Context context, AttributeSet attrs, int defStyle) {
|
|
super(context, attrs, defStyle);
|
|
}
|
|
|
|
@Override
|
|
protected void initDrawer(Context context, AttributeSet attrs, int defStyle) {
|
|
super.initDrawer(context, attrs, defStyle);
|
|
super.addView(mContentContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
|
if (USE_TRANSLATIONS) {
|
|
mContentContainer.setLayerType(View.LAYER_TYPE_NONE, null);
|
|
}
|
|
mContentContainer.setHardwareLayersEnabled(false);
|
|
super.addView(mMenuContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
|
mPeekSize = dpToPx(20);
|
|
}
|
|
|
|
@Override
|
|
protected void drawOverlay(Canvas canvas) {
|
|
final int width = getWidth();
|
|
final int height = getHeight();
|
|
final int offsetPixels = (int) mOffsetPixels;
|
|
final float openRatio = Math.abs(mOffsetPixels) / mMenuSize;
|
|
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
mMenuOverlay.setBounds(offsetPixels, 0, width, height);
|
|
break;
|
|
|
|
case RIGHT:
|
|
mMenuOverlay.setBounds(0, 0, width + offsetPixels, height);
|
|
break;
|
|
|
|
case TOP:
|
|
mMenuOverlay.setBounds(0, offsetPixels, width, height);
|
|
break;
|
|
|
|
case BOTTOM:
|
|
mMenuOverlay.setBounds(0, 0, width, height + offsetPixels);
|
|
break;
|
|
}
|
|
|
|
mMenuOverlay.setAlpha((int) (MAX_MENU_OVERLAY_ALPHA * openRatio));
|
|
mMenuOverlay.draw(canvas);
|
|
}
|
|
|
|
@Override
|
|
public void openMenu(boolean animate) {
|
|
int animateTo = 0;
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
case TOP:
|
|
animateTo = mMenuSize;
|
|
break;
|
|
|
|
case RIGHT:
|
|
case BOTTOM:
|
|
animateTo = -mMenuSize;
|
|
break;
|
|
}
|
|
|
|
animateOffsetTo(animateTo, 0, animate);
|
|
}
|
|
|
|
@Override
|
|
public void closeMenu(boolean animate) {
|
|
animateOffsetTo(0, 0, animate);
|
|
}
|
|
|
|
@Override
|
|
protected void onOffsetPixelsChanged(int offsetPixels) {
|
|
if (USE_TRANSLATIONS) {
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
mMenuContainer.setTranslationX(offsetPixels - mMenuSize);
|
|
break;
|
|
|
|
case TOP:
|
|
mMenuContainer.setTranslationY(offsetPixels - mMenuSize);
|
|
break;
|
|
|
|
case RIGHT:
|
|
mMenuContainer.setTranslationX(offsetPixels + mMenuSize);
|
|
break;
|
|
|
|
case BOTTOM:
|
|
mMenuContainer.setTranslationY(offsetPixels + mMenuSize);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (getPosition()) {
|
|
case TOP:
|
|
mMenuContainer.offsetTopAndBottom(offsetPixels - mMenuContainer.getBottom());
|
|
break;
|
|
|
|
case BOTTOM:
|
|
mMenuContainer.offsetTopAndBottom(offsetPixels - (mMenuContainer.getTop() - getHeight()));
|
|
break;
|
|
|
|
case LEFT:
|
|
mMenuContainer.offsetLeftAndRight(offsetPixels - mMenuContainer.getRight());
|
|
break;
|
|
|
|
case RIGHT:
|
|
mMenuContainer.offsetLeftAndRight(offsetPixels - (mMenuContainer.getLeft() - getWidth()));
|
|
break;
|
|
}
|
|
}
|
|
|
|
invalidate();
|
|
}
|
|
|
|
@Override
|
|
protected void initPeekScroller() {
|
|
switch (getPosition()) {
|
|
case RIGHT:
|
|
case BOTTOM: {
|
|
final int dx = -mPeekSize;
|
|
mPeekScroller.startScroll(0, 0, dx, 0, PEEK_DURATION);
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
final int dx = mPeekSize;
|
|
mPeekScroller.startScroll(0, 0, dx, 0, PEEK_DURATION);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
super.onSizeChanged(w, h, oldw, oldh);
|
|
onOffsetPixelsChanged((int) mOffsetPixels);
|
|
}
|
|
|
|
@Override
|
|
protected GradientDrawable.Orientation getDropShadowOrientation() {
|
|
switch (getPosition()) {
|
|
case TOP:
|
|
return GradientDrawable.Orientation.TOP_BOTTOM;
|
|
|
|
case RIGHT:
|
|
return GradientDrawable.Orientation.RIGHT_LEFT;
|
|
|
|
case BOTTOM:
|
|
return GradientDrawable.Orientation.BOTTOM_TOP;
|
|
|
|
default:
|
|
return GradientDrawable.Orientation.LEFT_RIGHT;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void updateDropShadowRect() {
|
|
final float openRatio = Math.abs(mOffsetPixels) / mMenuSize;
|
|
final int dropShadowSize = (int) (mDropShadowSize * openRatio);
|
|
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
mDropShadowRect.top = 0;
|
|
mDropShadowRect.bottom = getHeight();
|
|
mDropShadowRect.left = ViewHelper.getRight(mMenuContainer);
|
|
mDropShadowRect.right = mDropShadowRect.left + dropShadowSize;
|
|
break;
|
|
|
|
case TOP:
|
|
mDropShadowRect.left = 0;
|
|
mDropShadowRect.right = getWidth();
|
|
mDropShadowRect.top = ViewHelper.getBottom(mMenuContainer);
|
|
mDropShadowRect.bottom = mDropShadowRect.top + dropShadowSize;
|
|
break;
|
|
|
|
case RIGHT:
|
|
mDropShadowRect.top = 0;
|
|
mDropShadowRect.bottom = getHeight();
|
|
mDropShadowRect.right = ViewHelper.getLeft(mMenuContainer);
|
|
mDropShadowRect.left = mDropShadowRect.right - dropShadowSize;
|
|
break;
|
|
|
|
case BOTTOM:
|
|
mDropShadowRect.left = 0;
|
|
mDropShadowRect.right = getWidth();
|
|
mDropShadowRect.bottom = ViewHelper.getTop(mMenuContainer);
|
|
mDropShadowRect.top = mDropShadowRect.bottom - dropShadowSize;
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void startLayerTranslation() {
|
|
if (USE_TRANSLATIONS && mHardwareLayersEnabled && !mLayerTypeHardware) {
|
|
mLayerTypeHardware = true;
|
|
mMenuContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void stopLayerTranslation() {
|
|
if (mLayerTypeHardware) {
|
|
mLayerTypeHardware = false;
|
|
mMenuContainer.setLayerType(View.LAYER_TYPE_NONE, null);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
final int width = r - l;
|
|
final int height = b - t;
|
|
|
|
mContentContainer.layout(0, 0, width, height);
|
|
|
|
if (USE_TRANSLATIONS) {
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
mMenuContainer.layout(0, 0, mMenuSize, height);
|
|
break;
|
|
|
|
case RIGHT:
|
|
mMenuContainer.layout(width - mMenuSize, 0, width, height);
|
|
break;
|
|
|
|
case TOP:
|
|
mMenuContainer.layout(0, 0, width, mMenuSize);
|
|
break;
|
|
|
|
case BOTTOM:
|
|
mMenuContainer.layout(0, height - mMenuSize, width, height);
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
final int offsetPixels = (int) mOffsetPixels;
|
|
final int menuSize = mMenuSize;
|
|
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
mMenuContainer.layout(-menuSize + offsetPixels, 0, offsetPixels, height);
|
|
break;
|
|
|
|
case RIGHT:
|
|
mMenuContainer.layout(width + offsetPixels, 0, width + menuSize + offsetPixels, height);
|
|
break;
|
|
|
|
case TOP:
|
|
mMenuContainer.layout(0, -menuSize + offsetPixels, width, offsetPixels);
|
|
break;
|
|
|
|
case BOTTOM:
|
|
mMenuContainer.layout(0, height + offsetPixels, width, height + menuSize + offsetPixels);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
|
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
|
|
|
if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
|
|
throw new IllegalStateException("Must measure with an exact size");
|
|
}
|
|
|
|
final int width = MeasureSpec.getSize(widthMeasureSpec);
|
|
final int height = MeasureSpec.getSize(heightMeasureSpec);
|
|
|
|
if (mOffsetPixels == -1) openMenu(false);
|
|
|
|
int menuWidthMeasureSpec;
|
|
int menuHeightMeasureSpec;
|
|
switch (getPosition()) {
|
|
case TOP:
|
|
case BOTTOM:
|
|
menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);
|
|
menuHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, mMenuSize);
|
|
break;
|
|
|
|
default:
|
|
// LEFT/RIGHT
|
|
menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, mMenuSize);
|
|
menuHeightMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, height);
|
|
}
|
|
mMenuContainer.measure(menuWidthMeasureSpec, menuHeightMeasureSpec);
|
|
|
|
final int contentWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, width);
|
|
final int contentHeightMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, height);
|
|
mContentContainer.measure(contentWidthMeasureSpec, contentHeightMeasureSpec);
|
|
|
|
setMeasuredDimension(width, height);
|
|
|
|
updateTouchAreaSize();
|
|
}
|
|
|
|
private boolean isContentTouch(int x, int y) {
|
|
boolean contentTouch = false;
|
|
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
contentTouch = ViewHelper.getRight(mMenuContainer) < x;
|
|
break;
|
|
|
|
case RIGHT:
|
|
contentTouch = ViewHelper.getLeft(mMenuContainer) > x;
|
|
break;
|
|
|
|
case TOP:
|
|
contentTouch = ViewHelper.getBottom(mMenuContainer) < y;
|
|
break;
|
|
|
|
case BOTTOM:
|
|
contentTouch = ViewHelper.getTop(mMenuContainer) > y;
|
|
break;
|
|
}
|
|
|
|
return contentTouch;
|
|
}
|
|
|
|
protected boolean onDownAllowDrag(int x, int y) {
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
return (!mMenuVisible && mInitialMotionX <= mTouchSize)
|
|
|| (mMenuVisible && mInitialMotionX <= mOffsetPixels);
|
|
|
|
case RIGHT:
|
|
final int width = getWidth();
|
|
final int initialMotionX = (int) mInitialMotionX;
|
|
|
|
return (!mMenuVisible && initialMotionX >= width - mTouchSize)
|
|
|| (mMenuVisible && initialMotionX >= width + mOffsetPixels);
|
|
|
|
case TOP:
|
|
return (!mMenuVisible && mInitialMotionY <= mTouchSize)
|
|
|| (mMenuVisible && mInitialMotionY <= mOffsetPixels);
|
|
|
|
case BOTTOM:
|
|
final int height = getHeight();
|
|
return (!mMenuVisible && mInitialMotionY >= height - mTouchSize)
|
|
|| (mMenuVisible && mInitialMotionY >= height + mOffsetPixels);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected boolean onMoveAllowDrag(int x, int y, float dx, float dy) {
|
|
if (mMenuVisible && mTouchMode == TOUCH_MODE_FULLSCREEN) {
|
|
return true;
|
|
}
|
|
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
return (!mMenuVisible && mInitialMotionX <= mTouchSize && (dx > 0)) // Drawer closed
|
|
|| (mMenuVisible && x <= mOffsetPixels) // Drawer open
|
|
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible); // Drawer revealed
|
|
|
|
case RIGHT:
|
|
final int width = getWidth();
|
|
return (!mMenuVisible && mInitialMotionX >= width - mTouchSize && (dx < 0))
|
|
|| (mMenuVisible && x >= width - mOffsetPixels)
|
|
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible);
|
|
|
|
case TOP:
|
|
return (!mMenuVisible && mInitialMotionY <= mTouchSize && (dy > 0))
|
|
|| (mMenuVisible && x <= mOffsetPixels)
|
|
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible);
|
|
|
|
case BOTTOM:
|
|
final int height = getHeight();
|
|
return (!mMenuVisible && mInitialMotionY >= height - mTouchSize && (dy < 0))
|
|
|| (mMenuVisible && x >= height - mOffsetPixels)
|
|
|| (Math.abs(mOffsetPixels) <= mPeekSize && mMenuVisible);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected void onMoveEvent(float dx, float dy) {
|
|
switch (getPosition()) {
|
|
case LEFT:
|
|
setOffsetPixels(Math.min(Math.max(mOffsetPixels + dx, 0), mMenuSize));
|
|
break;
|
|
|
|
case RIGHT:
|
|
setOffsetPixels(Math.max(Math.min(mOffsetPixels + dx, 0), -mMenuSize));
|
|
break;
|
|
|
|
case TOP:
|
|
setOffsetPixels(Math.min(Math.max(mOffsetPixels + dy, 0), mMenuSize));
|
|
break;
|
|
|
|
case BOTTOM:
|
|
setOffsetPixels(Math.max(Math.min(mOffsetPixels + dy, 0), -mMenuSize));
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected void onUpEvent(int x, int y) {
|
|
final int offsetPixels = (int) mOffsetPixels;
|
|
|
|
switch (getPosition()) {
|
|
case LEFT: {
|
|
if (mIsDragging) {
|
|
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
|
|
final int initialVelocity = (int) getXVelocity(mVelocityTracker);
|
|
mLastMotionX = x;
|
|
animateOffsetTo(initialVelocity > 0 ? mMenuSize : 0, initialVelocity, true);
|
|
|
|
// Close the menu when content is clicked while the menu is visible.
|
|
} else if (mMenuVisible) {
|
|
closeMenu();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TOP: {
|
|
if (mIsDragging) {
|
|
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
|
|
final int initialVelocity = (int) getYVelocity(mVelocityTracker);
|
|
mLastMotionY = y;
|
|
animateOffsetTo(initialVelocity > 0 ? mMenuSize : 0, initialVelocity, true);
|
|
|
|
// Close the menu when content is clicked while the menu is visible.
|
|
} else if (mMenuVisible) {
|
|
closeMenu();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RIGHT: {
|
|
final int width = getWidth();
|
|
|
|
if (mIsDragging) {
|
|
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
|
|
final int initialVelocity = (int) getXVelocity(mVelocityTracker);
|
|
mLastMotionX = x;
|
|
animateOffsetTo(initialVelocity > 0 ? 0 : -mMenuSize, initialVelocity, true);
|
|
|
|
// Close the menu when content is clicked while the menu is visible.
|
|
} else if (mMenuVisible) {
|
|
closeMenu();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case BOTTOM: {
|
|
if (mIsDragging) {
|
|
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
|
|
final int initialVelocity = (int) getYVelocity(mVelocityTracker);
|
|
mLastMotionY = y;
|
|
animateOffsetTo(initialVelocity < 0 ? -mMenuSize : 0, initialVelocity, true);
|
|
|
|
// Close the menu when content is clicked while the menu is visible.
|
|
} else if (mMenuVisible) {
|
|
closeMenu();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected boolean checkTouchSlop(float dx, float dy) {
|
|
switch (getPosition()) {
|
|
case TOP:
|
|
case BOTTOM:
|
|
return Math.abs(dy) > mTouchSlop && Math.abs(dy) > Math.abs(dx);
|
|
|
|
default:
|
|
return Math.abs(dx) > mTouchSlop && Math.abs(dx) > Math.abs(dy);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void stopAnimation() {
|
|
super.stopAnimation();
|
|
removeCallbacks(mRevealRunnable);
|
|
}
|
|
|
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
|
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
|
|
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
|
removeCallbacks(mRevealRunnable);
|
|
mActivePointerId = INVALID_POINTER;
|
|
mIsDragging = false;
|
|
if (mVelocityTracker != null) {
|
|
mVelocityTracker.recycle();
|
|
mVelocityTracker = null;
|
|
}
|
|
|
|
if (Math.abs(mOffsetPixels) > mMenuSize / 2) {
|
|
openMenu();
|
|
} else {
|
|
closeMenu();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (action == MotionEvent.ACTION_DOWN && mMenuVisible && isCloseEnough()) {
|
|
setOffsetPixels(0);
|
|
stopAnimation();
|
|
endPeek();
|
|
setDrawerState(STATE_CLOSED);
|
|
mIsDragging = false;
|
|
}
|
|
|
|
// Always intercept events over the content while menu is visible.
|
|
if (mMenuVisible) {
|
|
int index = 0;
|
|
if (mActivePointerId != INVALID_POINTER) {
|
|
index = ev.findPointerIndex(mActivePointerId);
|
|
index = index == -1 ? 0 : index;
|
|
}
|
|
|
|
final int x = (int) ev.getX(index);
|
|
final int y = (int) ev.getY(index);
|
|
if (isContentTouch(x, y)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!mMenuVisible && !mIsDragging && mTouchMode == TOUCH_MODE_NONE) {
|
|
return false;
|
|
}
|
|
|
|
if (action != MotionEvent.ACTION_DOWN && mIsDragging) {
|
|
return true;
|
|
}
|
|
|
|
switch (action) {
|
|
case MotionEvent.ACTION_DOWN: {
|
|
mLastMotionX = mInitialMotionX = ev.getX();
|
|
mLastMotionY = mInitialMotionY = ev.getY();
|
|
final boolean allowDrag = onDownAllowDrag((int) mLastMotionX, (int) mLastMotionY);
|
|
mActivePointerId = ev.getPointerId(0);
|
|
|
|
if (allowDrag) {
|
|
setDrawerState(mMenuVisible ? STATE_OPEN : STATE_CLOSED);
|
|
stopAnimation();
|
|
endPeek();
|
|
|
|
if (!mMenuVisible && mInitialMotionX <= mPeekSize) {
|
|
postDelayed(mRevealRunnable, 160);
|
|
}
|
|
|
|
mIsDragging = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MotionEvent.ACTION_MOVE: {
|
|
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) {
|
|
mIsDragging = false;
|
|
mActivePointerId = INVALID_POINTER;
|
|
endDrag();
|
|
closeMenu(true);
|
|
return false;
|
|
}
|
|
|
|
final float x = ev.getX(pointerIndex);
|
|
final float dx = x - mLastMotionX;
|
|
final float y = ev.getY(pointerIndex);
|
|
final float dy = y - mLastMotionY;
|
|
|
|
if (Math.abs(dx) >= mTouchSlop || Math.abs(dy) >= mTouchSlop) {
|
|
removeCallbacks(mRevealRunnable);
|
|
endPeek();
|
|
}
|
|
|
|
if (checkTouchSlop(dx, dy)) {
|
|
if (mOnInterceptMoveEventListener != null && (mTouchMode == TOUCH_MODE_FULLSCREEN || mMenuVisible)
|
|
&& canChildrenScroll((int) dx, (int) dy, (int) x, (int) y)) {
|
|
endDrag(); // Release the velocity tracker
|
|
requestDisallowInterceptTouchEvent(true);
|
|
return false;
|
|
}
|
|
|
|
final boolean allowDrag = onMoveAllowDrag((int) x, (int) y, dx, dy);
|
|
|
|
if (allowDrag) {
|
|
endPeek();
|
|
stopAnimation();
|
|
setDrawerState(STATE_DRAGGING);
|
|
mIsDragging = true;
|
|
mLastMotionX = x;
|
|
mLastMotionY = y;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
onPointerUp(ev);
|
|
mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
|
|
mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
|
|
break;
|
|
}
|
|
|
|
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
|
|
mVelocityTracker.addMovement(ev);
|
|
|
|
return mIsDragging;
|
|
}
|
|
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent ev) {
|
|
if (!mMenuVisible && !mIsDragging && mTouchMode == TOUCH_MODE_NONE) {
|
|
return false;
|
|
}
|
|
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
|
|
|
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
|
|
mVelocityTracker.addMovement(ev);
|
|
|
|
switch (action) {
|
|
case MotionEvent.ACTION_DOWN: {
|
|
mLastMotionX = mInitialMotionX = ev.getX();
|
|
mLastMotionY = mInitialMotionY = ev.getY();
|
|
final boolean allowDrag = onDownAllowDrag((int) mLastMotionX, (int) mLastMotionY);
|
|
|
|
mActivePointerId = ev.getPointerId(0);
|
|
|
|
if (allowDrag) {
|
|
stopAnimation();
|
|
endPeek();
|
|
|
|
if (!mMenuVisible && mLastMotionX <= mPeekSize) {
|
|
postDelayed(mRevealRunnable, 160);
|
|
}
|
|
|
|
startLayerTranslation();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MotionEvent.ACTION_MOVE: {
|
|
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
|
|
if (pointerIndex == -1) {
|
|
mIsDragging = false;
|
|
mActivePointerId = INVALID_POINTER;
|
|
endDrag();
|
|
closeMenu(true);
|
|
return false;
|
|
}
|
|
|
|
if (!mIsDragging) {
|
|
final float x = ev.getX(pointerIndex);
|
|
final float dx = x - mLastMotionX;
|
|
final float y = ev.getY(pointerIndex);
|
|
final float dy = y - mLastMotionY;
|
|
|
|
if (checkTouchSlop(dx, dy)) {
|
|
final boolean allowDrag = onMoveAllowDrag((int) x, (int) y, dx, dy);
|
|
|
|
if (allowDrag) {
|
|
endPeek();
|
|
stopAnimation();
|
|
setDrawerState(STATE_DRAGGING);
|
|
mIsDragging = true;
|
|
mLastMotionX = x;
|
|
mLastMotionY = y;
|
|
} else {
|
|
mInitialMotionX = x;
|
|
mInitialMotionY = y;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mIsDragging) {
|
|
startLayerTranslation();
|
|
|
|
final float x = ev.getX(pointerIndex);
|
|
final float dx = x - mLastMotionX;
|
|
final float y = ev.getY(pointerIndex);
|
|
final float dy = y - mLastMotionY;
|
|
|
|
mLastMotionX = x;
|
|
mLastMotionY = y;
|
|
onMoveEvent(dx, dy);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MotionEvent.ACTION_CANCEL:
|
|
case MotionEvent.ACTION_UP: {
|
|
removeCallbacks(mRevealRunnable);
|
|
int index = ev.findPointerIndex(mActivePointerId);
|
|
index = index == -1 ? 0 : index;
|
|
final int x = (int) ev.getX(index);
|
|
final int y = (int) ev.getY(index);
|
|
onUpEvent(x, y);
|
|
mActivePointerId = INVALID_POINTER;
|
|
mIsDragging = false;
|
|
break;
|
|
}
|
|
|
|
case MotionEvent.ACTION_POINTER_DOWN:
|
|
final int index = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
|
|
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
|
mLastMotionX = ev.getX(index);
|
|
mLastMotionY = ev.getY(index);
|
|
mActivePointerId = ev.getPointerId(index);
|
|
break;
|
|
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
onPointerUp(ev);
|
|
mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
|
|
mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void onPointerUp(MotionEvent ev) {
|
|
final int pointerIndex = ev.getActionIndex();
|
|
final int pointerId = ev.getPointerId(pointerIndex);
|
|
if (pointerId == mActivePointerId) {
|
|
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
|
mLastMotionX = ev.getX(newPointerIndex);
|
|
mActivePointerId = ev.getPointerId(newPointerIndex);
|
|
if (mVelocityTracker != null) {
|
|
mVelocityTracker.clear();
|
|
}
|
|
}
|
|
}
|
|
}
|