package com.ijoomer.menubuilder; import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; public abstract class HorizontalDrawer extends DraggableDrawer { HorizontalDrawer(Activity activity, int dragMode) { super(activity, dragMode); } public HorizontalDrawer(Context context) { super(context); } public HorizontalDrawer(Context context, AttributeSet attrs) { super(context, attrs); } public HorizontalDrawer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { throw new IllegalStateException("Must measure with an exact size"); } final int width = MeasureSpec.getSize(widthMeasureSpec); final int height = MeasureSpec.getSize(heightMeasureSpec); if (!mMenuSizeSet) mMenuSize = (int) (width * 0.8f); if (mOffsetPixels == -1) openMenu(false); final int menuWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, mMenuSize); final int 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(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction() & MotionEvent.ACTION_MASK; if (action == MotionEvent.ACTION_DOWN && mMenuVisible && isCloseEnough()) { setOffsetPixels(0); stopAnimation(); endPeek(); setDrawerState(STATE_CLOSED); } // Always intercept events over the content while menu is visible. if (mMenuVisible && isContentTouch(ev)) return true; if (mTouchMode == TOUCH_MODE_NONE) { return false; } if (action != MotionEvent.ACTION_DOWN) { if (mIsDragging) return true; } switch (action) { case MotionEvent.ACTION_DOWN: { mLastMotionX = mInitialMotionX = ev.getX(); mLastMotionY = mInitialMotionY = ev.getY(); final boolean allowDrag = onDownAllowDrag(ev); if (allowDrag) { setDrawerState(mMenuVisible ? STATE_OPEN : STATE_CLOSED); stopAnimation(); endPeek(); mIsDragging = false; } break; } case MotionEvent.ACTION_MOVE: { final float x = ev.getX(); final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = ev.getY(); final float yDiff = Math.abs(y - mLastMotionY); if (xDiff > mTouchSlop && xDiff > yDiff) { if (mOnInterceptMoveEventListener != null && mTouchMode == TOUCH_MODE_FULLSCREEN && canChildScrollHorizontally(mContentContainer, false, (int) dx, (int) x, (int) y)) { endDrag(); // Release the velocity tracker return false; } final boolean allowDrag = onMoveAllowDrag(ev, dx); if (allowDrag) { setDrawerState(STATE_DRAGGING); mIsDragging = true; mLastMotionX = x; mLastMotionY = y; } } break; } /** * If you click really fast, an up or cancel event is delivered here. * Just snap content to whatever is closest. * */ case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { if (Math.abs(mOffsetPixels) > mMenuSize / 2) { openMenu(); } else { closeMenu(); } 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(ev); if (allowDrag) { stopAnimation(); endPeek(); startLayerTranslation(); } break; } case MotionEvent.ACTION_MOVE: { if (!mIsDragging) { final float x = ev.getX(); final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = ev.getY(); final float yDiff = Math.abs(y - mLastMotionY); if (xDiff > mTouchSlop && xDiff > yDiff) { final boolean allowDrag = onMoveAllowDrag(ev, dx); if (allowDrag) { setDrawerState(STATE_DRAGGING); mIsDragging = true; mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : mInitialMotionX - mTouchSlop; } } } if (mIsDragging) { startLayerTranslation(); final float x = ev.getX(); final float dx = x - mLastMotionX; mLastMotionX = x; onMoveEvent(dx); } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { onUpEvent(ev); break; } } return true; } }