@Override public boolean onInterceptTouchEvent(MotionEvent event) { final int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); if (mAnimating) { return false; } View leftHandle = mLeftSlider.tab; leftHandle.getHitRect(mTmpRect); boolean leftHit = mTmpRect.contains((int) x, (int) y); View rightHandle = mRightSlider.tab; rightHandle.getHitRect(mTmpRect); boolean rightHit = mTmpRect.contains((int) x, (int) y); if (!mTracking && !(leftHit || rightHit)) { return false; } switch (action) { case MotionEvent.ACTION_DOWN: { mTracking = true; mTriggered = false; vibrate(VIBRATE_SHORT); if (leftHit) { mCurrentSlider = mLeftSlider; mOtherSlider = mRightSlider; mThreshold = isHorizontal() ? THRESHOLD : 1.0f - THRESHOLD; setGrabbedState(OnTriggerListener.LEFT_HANDLE); } else { mCurrentSlider = mRightSlider; mOtherSlider = mLeftSlider; mThreshold = isHorizontal() ? 1.0f - THRESHOLD : THRESHOLD; setGrabbedState(OnTriggerListener.RIGHT_HANDLE); } mCurrentSlider.setState(Slider.STATE_PRESSED); mCurrentSlider.showTarget(); mOtherSlider.hide(); break; } } return true; }
private static boolean isTouchEventHandled(final View view, final MotionEvent event) { if (view instanceof RightPaneBackgroundView) return false; if (!(view instanceof ViewGroup)) return true; final MotionEvent ev = MotionEvent.obtain(event); final float xf = ev.getX(); final float yf = ev.getY(); final float scrolledXFloat = xf + view.getScrollX(); final float scrolledYFloat = yf + view.getScrollY(); final Rect frame = new Rect(); final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final int count = ((ViewGroup) view).getChildCount(); for (int i = count - 1; i >= 0; i--) { final View child = ((ViewGroup) view).getChildAt(i); if (child.isShown() || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { // offset the event to the view's coordinate system final float xc = scrolledXFloat - child.getLeft(); final float yc = scrolledYFloat - child.getTop(); ev.setLocation(xc, yc); if (isTouchEventHandled(child, ev)) return true; } } } return false; }
private void drawShadow(Canvas canvas, View child) { final Rect childRect = mTmpRect; child.getHitRect(childRect); if ((mEdgeFlag & EDGE_LEFT) != 0) { mShadowLeft.setBounds( childRect.left - mShadowLeft.getIntrinsicWidth(), childRect.top, childRect.left, childRect.bottom); mShadowLeft.setAlpha((int) (mScrimOpacity * FULL_ALPHA)); mShadowLeft.draw(canvas); } if ((mEdgeFlag & EDGE_RIGHT) != 0) { mShadowRight.setBounds( childRect.right, childRect.top, childRect.right + mShadowRight.getIntrinsicWidth(), childRect.bottom); mShadowRight.setAlpha((int) (mScrimOpacity * FULL_ALPHA)); mShadowRight.draw(canvas); } if ((mEdgeFlag & EDGE_BOTTOM) != 0) { mShadowBottom.setBounds( childRect.left, childRect.bottom, childRect.right, childRect.bottom + mShadowBottom.getIntrinsicHeight()); mShadowBottom.setAlpha((int) (mScrimOpacity * FULL_ALPHA)); mShadowBottom.draw(canvas); } }
/** * Duplicate touch events to child views. We want to dispatch a down motion event and the move * events to child views, but calling dispatchTouchEvent() causes StackOverflowError. Therefore we * do it manually. * * @param ev motion event to be passed to children * @param pendingEvents pending events like ACTION_DOWN. This will be passed to the children * before ev */ private void duplicateTouchEventForChildren(MotionEvent ev, MotionEvent... pendingEvents) { if (ev == null) { return; } for (int i = getChildCount() - 1; 0 <= i; i--) { View childView = getChildAt(i); if (childView != null) { Rect childRect = new Rect(); childView.getHitRect(childRect); MotionEvent event = MotionEvent.obtainNoHistory(ev); if (!childRect.contains((int) event.getX(), (int) event.getY())) { continue; } float offsetX = -childView.getLeft(); float offsetY = -childView.getTop(); boolean consumed = false; if (pendingEvents != null) { for (MotionEvent pe : pendingEvents) { if (pe != null) { MotionEvent peAdjusted = MotionEvent.obtainNoHistory(pe); peAdjusted.offsetLocation(offsetX, offsetY); consumed |= childView.dispatchTouchEvent(peAdjusted); } } } event.offsetLocation(offsetX, offsetY); consumed |= childView.dispatchTouchEvent(event); if (consumed) { break; } } } }
@Override public boolean onInterceptTouchEvent(View view, MotionEvent event) { // We need to account for scroll state for the touched view otherwise // tapping on an "empty" part of the view will still be considered a // valid touch event. if (view.getScrollX() != 0 || view.getScrollY() != 0) { Rect rect = new Rect(); view.getHitRect(rect); rect.offset(-view.getScrollX(), -view.getScrollY()); int[] viewCoords = new int[2]; view.getLocationOnScreen(viewCoords); int x = (int) event.getRawX() - viewCoords[0]; int y = (int) event.getRawY() - viewCoords[1]; if (!rect.contains(x, y)) return false; } // If the tab tray is showing, hide the tab tray and don't send the event to content. if (event.getActionMasked() == MotionEvent.ACTION_DOWN && autoHideTabs()) { mIsHidingTabs = true; return true; } return false; }
private boolean isInIgnoredView(MotionEvent ev) { Rect rect = new Rect(); for (View v : mIgnoredViews) { v.getHitRect(rect); if (rect.contains((int) ev.getX(), (int) ev.getY())) return true; } return false; }
/** * 检查UI事件是否发生在视图view的区域内 * * @param v * @param ev * @return */ public static boolean intersects(View v, MotionEvent ev) { if (v == null) return false; Rect rect = new Rect(); v.getHitRect(rect); Rect r = new Rect(); r.left = r.right = (int) ev.getX(); r.bottom = r.top = (int) ev.getY(); return rect.intersects(r.left, r.top, r.right, r.bottom); }
public boolean isTransformedTouchPointInView(float x, float y, View child) { // TODO: confirm if this is the right approach if (child == null) return false; final Rect frame = new Rect(); child.getHitRect(frame); return frame.contains((int) x, (int) y); }
/* * pointToPosition() doesn't consider invisible views, but we need to, so * implement a slightly different version. */ private int myPointToPosition(final int x, final int y) { Rect frame = this.mTempRect; final int count = this.getChildCount(); for (int i = count - 1; i >= 0; i--) { final View child = this.getChildAt(i); child.getHitRect(frame); if (frame.contains(x, y)) { return this.getFirstVisiblePosition() + i; } } return INVALID_POSITION; }
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (((!mEnabled || !mInterceptTouch) && mMode == MODE_READY) || mAlwaysOpened) { return super.dispatchTouchEvent(ev); } if (mMode != MODE_FINISHED) { onTouchEvent(ev); if (mMode != MODE_SLIDE) { super.dispatchTouchEvent(ev); } else { MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent.setAction(MotionEvent.ACTION_CANCEL); super.dispatchTouchEvent(cancelEvent); cancelEvent.recycle(); } return true; } else { final int action = ev.getAction(); Rect rect = new Rect(); View menu = getChildAt(0); menu.getHitRect(rect); if (!rect.contains((int) ev.getX(), (int) ev.getY())) { if (action == MotionEvent.ACTION_UP && mCloseOnRelease && !mDispatchWhenOpened) { close(); mCloseOnRelease = false; } else { if (action == MotionEvent.ACTION_DOWN && !mDispatchWhenOpened) { mCloseOnRelease = true; } onTouchEvent(ev); } if (mDispatchWhenOpened) { super.dispatchTouchEvent(ev); } return true; } else { onTouchEvent(ev); ev.offsetLocation(-menu.getLeft(), -menu.getTop()); menu.dispatchTouchEvent(ev); return true; } } }
private boolean isPinnedViewTouched(View view, float x, float y) { view.getHitRect(mTouchRect); // by taping top or bottom padding, the list performs on click on a border item. // we don't add top padding here to keep behavior consistent. mTouchRect.top += mTranslateY; mTouchRect.bottom += mTranslateY + getPaddingTop(); mTouchRect.left += getPaddingLeft(); mTouchRect.right -= getPaddingRight(); return mTouchRect.contains((int) x, (int) y); }
/** * Detect if the given {@link MotionEvent} is outside the boundaries of this window, which usually * means we should dismiss. */ protected void detectEventOutside(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { // Only try detecting outside events on down-press mDecor.getHitRect(mRect); mRect.top = mRect.top + mShadowTouch; mRect.bottom = mRect.bottom - mShadowTouch; final int x = (int) event.getX(); final int y = (int) event.getY(); if (!mRect.contains(x, y)) { event.setAction(MotionEvent.ACTION_OUTSIDE); } } }
@Override public boolean onInterceptTouchEvent(MotionEvent event) { if (mTopCard == null) { return false; } if (mGestureDetector.onTouchEvent(event)) { return true; } final int pointerIndex; final float x, y; final float dx, dy; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mTopCard.getHitRect(childRect); CardModel cardModel = (CardModel) getAdapter().getItem(getChildCount() - 1); if (cardModel.getOnClickListener() != null) { cardModel.getOnClickListener().OnClickListener(); } pointerIndex = event.getActionIndex(); x = event.getX(pointerIndex); y = event.getY(pointerIndex); if (!childRect.contains((int) x, (int) y)) { return false; } mLastTouchX = x; mLastTouchY = y; mActivePointerId = event.getPointerId(pointerIndex); break; case MotionEvent.ACTION_MOVE: pointerIndex = event.findPointerIndex(mActivePointerId); x = event.getX(pointerIndex); y = event.getY(pointerIndex); if (Math.abs(x - mLastTouchX) > mTouchSlop || Math.abs(y - mLastTouchY) > mTouchSlop) { float[] points = new float[] {x - mTopCard.getLeft(), y - mTopCard.getTop()}; mTopCard.getMatrix().invert(mMatrix); mMatrix.mapPoints(points); mTopCard.setPivotX(points[0]); mTopCard.setPivotY(points[1]); return true; } } return false; }
@Override public boolean onInterceptTouchEvent(MotionEvent event) { if (mLocked) { return false; } final int action = event.getAction(); float x = event.getX(); float y = event.getY(); final Rect frame = mFrame; final View handle = mHandle; handle.getHitRect(frame); if (!mTracking && !frame.contains((int) x, (int) y)) { return false; } if (action == MotionEvent.ACTION_DOWN) { mTracking = true; handle.setPressed(true); // Must be called before prepareTracking() prepareContent(); // Must be called after prepareContent() if (mOnDrawerScrollListener != null) { mOnDrawerScrollListener.onScrollStarted(); } if (mVertical) { final int top = mHandle.getTop(); mTouchDelta = (int) y - top; prepareTracking(top); } else { final int left = mHandle.getLeft(); mTouchDelta = (int) x - left; prepareTracking(left); } mVelocityTracker.addMovement(event); } return true; }
private boolean isEventOverChild(MotionEvent ev, List<View> children) { final int actionIndex = ev.getActionIndex(); final float x = ev.getX(actionIndex) + getScrollX(); final float y = ev.getY(actionIndex) + getScrollY(); for (View child : children) { if (!canViewReceivePointerEvents(child)) { continue; } child.getHitRect(sHitFrame); // child can receive the motion event. if (sHitFrame.contains((int) x, (int) y)) { return true; } } return false; }
/** * Maps a point to a position in the list. * * @param x X in local coordinate * @param y Y in local coordinate * @return The position of the item which contains the specified point, or {@link * #INVALID_POSITION} if the point does not intersect an item. */ public int pointToPosition(int x, int y) { Rect frame = mTouchFrame; if (frame == null) { mTouchFrame = new Rect(); frame = mTouchFrame; } final int count = getChildCount(); for (int i = count - 1; i >= 0; i--) { View child = getChildAt(i); if (child.getVisibility() == View.VISIBLE) { child.getHitRect(frame); if (frame.contains(x, y)) { return mFirstPosition + i; } } } return INVALID_POSITION; }
@Override public void onDraw(Canvas c) { super.onDraw(c); if (!DEBUG) return; Paint pt = new Paint(); pt.setStyle(Paint.Style.STROKE); pt.setColor(0xFFCCCCCC); pt.setStrokeWidth(2.0f); final Rect check = new Rect(); final int N = getChildCount(); for (int i = 0; i < N; i++) { View stone = getChildAt(i); stone.getHitRect(check); c.drawRect(check, pt); } }
private boolean findClickableViewInChild(View view, int x, int y) { if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) { View child = viewGroup.getChildAt(i); final Rect rect = new Rect(); child.getHitRect(rect); final boolean contains = rect.contains(x, y); if (contains) { return findClickableViewInChild(child, x - rect.left, y - rect.top); } } } else if (view != childView) { return (view.isEnabled() && (view.isClickable() || view.isLongClickable() || view.isFocusableInTouchMode())); } return view.isFocusableInTouchMode(); }
/** 滑动开始准备 */ private void actionDown(MotionEvent motionEvent) { if (mPaused) { return; } // 找到被点击的 view 和位置(包括 top left right bottom) Rect rect = new Rect(); int childCount = mRecyclerView.getChildCount(); // location 指的是 RecyclerView 左上角以整个屏幕的左上角为参照物的坐标 int[] location = new int[2]; mRecyclerView.getLocationOnScreen(location); // 此处的 x y 指的是触摸点以 location 为参照物时的坐标 int x = (int) motionEvent.getRawX() - location[0]; int y = (int) motionEvent.getRawY() - location[1]; View child; for (int i = 0; i < childCount; i++) { child = mRecyclerView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } // 找到相应的 view 并且该 view 不处于执行动画状态 if (mDownView != null && mAnimatingPosition != mRecyclerView.getChildAdapterPosition(mDownView)) { mAlpha = mDownView.getAlpha(); mDownX = motionEvent.getRawX(); mDownY = motionEvent.getRawY(); mDownPosition = mRecyclerView.getChildAdapterPosition(mDownView); if (mSwipeListener.canSwipe(mDownPosition)) { // ?添加速度追踪器 mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); } else { mDownView = null; } } }
/* * pointToPosition() doesn't consider invisible views, but we need to, so * implement a slightly different version. */ private int myPointToPosition(int x, int y) { if (y < 0) { // when dragging off the top of the screen, calculate position // by going back from a visible item int pos = myPointToPosition(x, y + mItemHeightNormal); if (pos > 0) { return pos - 1; } } Rect frame = mTempRect; final int count = getChildCount(); for (int i = count - 1; i >= 0; i--) { final View child = getChildAt(i); child.getHitRect(frame); if (frame.contains(x, y)) { return getFirstVisiblePosition() + i; } } return INVALID_POSITION; }
private DropTarget findDropTarget(ViewGroup container, int x, int y, int[] dropCoordinates) { final Rect r = mDragRect; final int count = container.getChildCount(); final int scrolledX = x + container.getScrollX(); final int scrolledY = y + container.getScrollY(); final View ignoredDropTarget = mIgnoredDropTarget; for (int i = count - 1; i >= 0; i--) { final View child = container.getChildAt(i); if (child.getVisibility() == VISIBLE && child != ignoredDropTarget) { child.getHitRect(r); if (r.contains(scrolledX, scrolledY)) { DropTarget target = null; if (child instanceof ViewGroup) { x = scrolledX - child.getLeft(); y = scrolledY - child.getTop(); target = findDropTarget((ViewGroup) child, x, y, dropCoordinates); } if (target == null) { if (child instanceof DropTarget) { // Only consider this child if they will accept DropTarget childTarget = (DropTarget) child; if (childTarget.acceptDrop(mDragSource, x, y, 0, 0, mDragInfo)) { dropCoordinates[0] = x; dropCoordinates[1] = y; return (DropTarget) child; } else { return null; } } } else { return target; } } } } return null; }
protected void applyTransformation(float f, Transformation transformation) { super.applyTransformation(f, transformation); if (mAnimType == 1) { if (f < 1.0F) { int i = Math.max((int) ((float) mFullHeight * f), mMinHeight); mView.getLayoutParams().height = i; } else { mView.getLayoutParams().height = mFullHeight; } if (mShowExpandedArea) { if (mRect == null) { mRect = new Rect(); } mView.getHitRect(mRect); mView.requestRectangleOnScreen(mRect); } } else if (f < 1.0F) { int j = Math.max(mFullHeight - (int) ((float) mFullHeight * f), mMinHeight); mView.getLayoutParams().height = j; } else { mView.getLayoutParams().height = mMinHeight; } mView.requestLayout(); }
public boolean photoOffTable(final View photo, final int dx, final int dy) { Rect hit = new Rect(); photo.getHitRect(hit); hit.offset(dx, dy); return (hit.bottom < 0f || hit.top > getHeight() || hit.right < 0f || hit.left > getWidth()); }
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if (mViewWidth < 2) { mViewWidth = mListView.getWidth(); } switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (mPaused) { return false; } if (mSwiping) { return true; } // TODO: ensure this is a finger, and set a flag // Find the child view that was touched (perform a hit test) Rect rect = new Rect(); int childCount = mListView.getChildCount(); int headerCount = mListView.getHeaderViewsCount(); int footerCount = mListView.getFooterViewsCount(); int[] listViewCoords = new int[2]; mListView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child = null; for (int i = headerCount; i < (childCount - footerCount); i++) { child = mListView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } if (mDownView != null) { mDownX = motionEvent.getRawX(); mDownY = motionEvent.getRawY(); mDownPosition = mListView.getPositionForView(mDownView); if (mDownPosition != ListView.INVALID_POSITION && mDownPosition < mListView.getAdapter().getCount()) { if (mListView.getAdapter().getItem(mDownPosition) instanceof Card) { if (mCallbacks.canDismiss( mDownPosition, (Card) mListView.getAdapter().getItem(mDownPosition))) { mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); } else { mDownView = null; } } else { mDownView = null; } } else { mDownView = null; } } view.onTouchEvent(motionEvent); return true; // return false; } case MotionEvent.ACTION_UP: { if (mVelocityTracker == null) { break; } float deltaX = motionEvent.getRawX() - mDownX; mVelocityTracker.addMovement(motionEvent); mVelocityTracker.computeCurrentVelocity(1000); float velocityX = mVelocityTracker.getXVelocity(); float absVelocityX = Math.abs(velocityX); float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); boolean dismiss = false; boolean dismissRight = false; if (Math.abs(deltaX) > mViewWidth / swipeDistanceDivisor && mSwiping) { dismiss = true; dismissRight = deltaX > 0; } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity && absVelocityY < absVelocityX && mSwiping) { // dismiss only if flinging in the same direction as dragging dismiss = (velocityX < 0) == (deltaX < 0); dismissRight = mVelocityTracker.getXVelocity() > 0; } if (dismiss && mDownPosition != ListView.INVALID_POSITION) { // dismiss dismiss(mDownView, mDownPosition - mListView.getHeaderViewsCount(), dismissRight); } else { // cancel mDownView .animate() .translationX(0) .alpha(1) .setDuration(mAnimationTime) .setListener(null); } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; if (mSwiping) { // To prevent onClick event with a fast swipe mSwiping = false; return true; } mSwiping = false; break; } case MotionEvent.ACTION_CANCEL: { if (mVelocityTracker == null) { break; } if (mDownView != null) { // cancel mDownView .animate() .translationX(0) .alpha(1) .setDuration(mAnimationTime) .setListener(null); } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; break; } case MotionEvent.ACTION_MOVE: { if (mVelocityTracker == null || mPaused) { break; } mVelocityTracker.addMovement(motionEvent); float deltaX = motionEvent.getRawX() - mDownX; float deltaY = motionEvent.getRawY() - mDownY; boolean movementAllowed = isSwipeMovementAllowed(deltaX); if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2 && movementAllowed) { mSwiping = true; mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop); mListView.requestDisallowInterceptTouchEvent(true); // Cancel ListView's touch (un-highlighting the item) MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); cancelEvent.setAction( MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); mListView.onTouchEvent(cancelEvent); view.onTouchEvent(cancelEvent); cancelEvent.recycle(); } if (mSwiping) { mDownView.setTranslationX(deltaX - mSwipingSlop); mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth))); return true; } break; } } return false; }
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if (mViewWidth < 2) { mViewWidth = mListView.getWidth(); } switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (mPaused) { return false; } // TODO: ensure this is a finger, and set a flag // Find the child view that was touched (perform a hit test) Rect rect = new Rect(); int childCount = mListView.getChildCount(); int[] listViewCoords = new int[2]; mListView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child; for (int i = 0; i < childCount; i++) { child = mListView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } if (mDownView != null) { mDownX = motionEvent.getRawX(); mDownPosition = mListView.getPositionForView(mDownView); if (((ListItem) mListView.getAdapter().getItem(mDownPosition)).getId() < 0) { return true; } mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); } view.onTouchEvent(motionEvent); return true; } case MotionEvent.ACTION_UP: { if (mVelocityTracker == null) { break; } float deltaX = motionEvent.getRawX() - mDownX; mVelocityTracker.addMovement(motionEvent); mVelocityTracker.computeCurrentVelocity(1000); float velocityX = Math.abs(mVelocityTracker.getXVelocity()); float velocityY = Math.abs(mVelocityTracker.getYVelocity()); boolean dismiss = false; boolean dismissRight = false; if (Math.abs(deltaX) > mViewWidth / 2) { dismiss = true; dismissRight = deltaX > 0; } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity && velocityY < velocityX) { dismiss = true; dismissRight = mVelocityTracker.getXVelocity() > 0; } if (dismiss) { // dismiss final View downView = mDownView; // mDownView gets null'd before animation ends final int downPosition = mDownPosition; ++mDismissAnimationRefCount; animate(mDownView) .translationX(dismissRight ? mViewWidth : -mViewWidth) .alpha(0) .setDuration(mAnimationTime) .setListener( new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { performDismiss(downView, downPosition); } }); } else { // cancel animate(mDownView) .translationX(0) .alpha(1) .setDuration(mAnimationTime) .setListener(null); } mVelocityTracker = null; mDownX = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; break; } case MotionEvent.ACTION_MOVE: { if (mVelocityTracker == null || mPaused) { break; } mVelocityTracker.addMovement(motionEvent); float deltaX = motionEvent.getRawX() - mDownX; if (Math.abs(deltaX) > mSlop) { mSwiping = true; mListView.requestDisallowInterceptTouchEvent(true); // Cancel ListView's touch (un-highlighting the item) MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); cancelEvent.setAction( MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); mListView.onTouchEvent(cancelEvent); } if (mSwiping) { setTranslationX(mDownView, deltaX); setAlpha( mDownView, Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth))); return true; } break; } } return false; }
private boolean handleTouchEvent(MotionEvent motionEvent) { if (mViewWidth < 2) { mViewWidth = mRecyclerView.getWidth(); } switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (mPaused) { break; } // Find the child view that was touched (perform a hit test) Rect rect = new Rect(); int childCount = mRecyclerView.getChildCount(); int[] listViewCoords = new int[2]; mRecyclerView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child; for (int i = 0; i < childCount; i++) { child = mRecyclerView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } if (mDownView != null) { mDownX = motionEvent.getRawX(); mDownY = motionEvent.getRawY(); mDownPosition = mRecyclerView.getChildAdapterPosition(mDownView); mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); mFgView = mDownView.findViewById(mFgID); } break; } case MotionEvent.ACTION_CANCEL: { if (mVelocityTracker == null) { break; } if (mDownView != null && mSwiping) { // cancel mFgView.animate().translationX(0).setDuration(ANIMATION_FAST).setListener(null); } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; mBgView = null; break; } case MotionEvent.ACTION_UP: { if (mVelocityTracker == null) { break; } mFinalDelta = motionEvent.getRawX() - mDownX; mVelocityTracker.addMovement(motionEvent); mVelocityTracker.computeCurrentVelocity(1000); float velocityX = mVelocityTracker.getXVelocity(); float absVelocityX = Math.abs(velocityX); float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); boolean dismiss = false; boolean dismissRight = false; if (Math.abs(mFinalDelta) > mViewWidth / 2 && mSwiping) { dismiss = true; dismissRight = mFinalDelta > 0; } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity && absVelocityY < absVelocityX && mSwiping) { // dismiss only if flinging in the same direction as dragging dismiss = (velocityX < 0) == (mFinalDelta < 0); dismissRight = mVelocityTracker.getXVelocity() > 0; } if (dismiss && mDownPosition != ListView.INVALID_POSITION && mSwipeListener.canSwipe(mDownPosition)) { // dismiss ++mDismissAnimationRefCount; mBgView.animate().alpha(1).setDuration(ANIMATION_FAST); mFgView .animate() .translationX(dismissRight ? mViewWidth : -mViewWidth) .setDuration(ANIMATION_FAST) .setListener( new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mFgView.animate().translationX(0); // Esto hace que regrese a su posision :) } }); } else { // cancel mFgView.animate().translationX(0).setDuration(ANIMATION_FAST).setListener(null); } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; mBgView = null; break; } case MotionEvent.ACTION_MOVE: { if (mVelocityTracker == null || mPaused) { break; } mVelocityTracker.addMovement(motionEvent); float deltaX = motionEvent.getRawX() - mDownX; float deltaY = motionEvent.getRawY() - mDownY; if (!mSwiping && Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) { mSwiping = true; mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop); } if (mSwiping) { if (mBgView == null) { mBgView = mDownView.findViewById(mBgID); mBgView.setVisibility(View.VISIBLE); listener.holaView((deltaX - mSwipingSlop) > 0, mBgView); } mFgView.setTranslationX(deltaX - mSwipingSlop); return true; } break; } } return false; }
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); final CellInfo cellInfo = mCellInfo; if (action == MotionEvent.ACTION_DOWN) { final Rect frame = mRect; final int x = (int) ev.getX() + mScrollX; final int y = (int) ev.getY() + mScrollY; final int count = getChildCount(); boolean found = false; for (int i = count - 1; i >= 0; i--) { final View child = getChildAt(i); if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(x, y)) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); cellInfo.cell = child; cellInfo.cellX = lp.cellX; cellInfo.cellY = lp.cellY; cellInfo.spanX = lp.cellHSpan; cellInfo.spanY = lp.cellVSpan; cellInfo.valid = true; found = true; mDirtyTag = false; break; } } } mLastDownOnOccupiedCell = found; if (!found) { int cellXY[] = mCellXY; pointToCellExact(x, y, cellXY); final boolean portrait = mPortrait; final int xCount = portrait ? mShortAxisCells : mLongAxisCells; final int yCount = portrait ? mLongAxisCells : mShortAxisCells; final boolean[][] occupied = mOccupied; findOccupiedCells(xCount, yCount, occupied, null); cellInfo.cell = null; cellInfo.cellX = cellXY[0]; cellInfo.cellY = cellXY[1]; cellInfo.spanX = 1; cellInfo.spanY = 1; cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount && cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]]; // Instead of finding the interesting vacant cells here, wait until a // caller invokes getTag() to retrieve the result. Finding the vacant // cells is a bit expensive and can generate many new objects, it's // therefore better to defer it until we know we actually need it. mDirtyTag = true; } setTag(cellInfo); } else if (action == MotionEvent.ACTION_UP) { cellInfo.cell = null; cellInfo.cellX = -1; cellInfo.cellY = -1; cellInfo.spanX = 0; cellInfo.spanY = 0; cellInfo.valid = false; mDirtyTag = false; setTag(cellInfo); } return false; }
private void moveHandle(int position) { final View handle = mHandle; if (mVertical) { if (position == EXPANDED_FULL_OPEN) { handle.offsetTopAndBottom(mTopOffset - handle.getTop()); invalidate(); } else if (position == COLLAPSED_FULL_CLOSED) { handle.offsetTopAndBottom(mBottomOffset + mBottom - mTop - mHandleHeight - handle.getTop()); invalidate(); } else { final int top = handle.getTop(); int deltaY = position - top; if (position < mTopOffset) { deltaY = mTopOffset - top; } else if (deltaY > mBottomOffset + mBottom - mTop - mHandleHeight - top) { deltaY = mBottomOffset + mBottom - mTop - mHandleHeight - top; } handle.offsetTopAndBottom(deltaY); final Rect frame = mFrame; final Rect region = mInvalidate; handle.getHitRect(frame); region.set(frame); region.union(frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY); region.union( 0, frame.bottom - deltaY, getWidth(), frame.bottom - deltaY + mContent.getHeight()); invalidate(region); } } else { if (position == EXPANDED_FULL_OPEN) { handle.offsetLeftAndRight(mTopOffset - handle.getLeft()); invalidate(); } else if (position == COLLAPSED_FULL_CLOSED) { handle.offsetLeftAndRight(mBottomOffset + mRight - mLeft - mHandleWidth - handle.getLeft()); invalidate(); } else { final int left = handle.getLeft(); int deltaX = position - left; if (position < mTopOffset) { deltaX = mTopOffset - left; } else if (deltaX > mBottomOffset + mRight - mLeft - mHandleWidth - left) { deltaX = mBottomOffset + mRight - mLeft - mHandleWidth - left; } handle.offsetLeftAndRight(deltaX); final Rect frame = mFrame; final Rect region = mInvalidate; handle.getHitRect(frame); region.set(frame); region.union(frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom); region.union( frame.right - deltaX, 0, frame.right - deltaX + mContent.getWidth(), getHeight()); invalidate(region); } } }
@Override public boolean onTouchEvent(MotionEvent event) { if (mTopCard == null) { return false; } if (mGestureDetector.onTouchEvent(event)) { return true; } // Log.d("Touch Event", MotionEvent.actionToString(event.getActionMasked()) + " "); final int pointerIndex; final float x, y; final float dx, dy; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mTopCard.getHitRect(childRect); pointerIndex = event.getActionIndex(); x = event.getX(pointerIndex); y = event.getY(pointerIndex); if (!childRect.contains((int) x, (int) y)) { return false; } mLastTouchX = x; mLastTouchY = y; mActivePointerId = event.getPointerId(pointerIndex); float[] points = new float[] {x - mTopCard.getLeft(), y - mTopCard.getTop()}; mTopCard.getMatrix().invert(mMatrix); mMatrix.mapPoints(points); mTopCard.setPivotX(points[0]); mTopCard.setPivotY(points[1]); break; case MotionEvent.ACTION_MOVE: pointerIndex = event.findPointerIndex(mActivePointerId); x = event.getX(pointerIndex); y = event.getY(pointerIndex); dx = x - mLastTouchX; dy = y - mLastTouchY; if (Math.abs(dx) > mTouchSlop || Math.abs(dy) > mTouchSlop) { mDragging = true; } if (!mDragging) { return true; } mTopCard.setTranslationX(mTopCard.getTranslationX() + dx); mTopCard.setTranslationY(mTopCard.getTranslationY() + dy); mTopCard.setRotation(40 * mTopCard.getTranslationX() / (getWidth() / 2.f)); mLastTouchX = x; mLastTouchY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (!mDragging) { return true; } mDragging = false; mActivePointerId = INVALID_POINTER_ID; ValueAnimator animator = ObjectAnimator.ofPropertyValuesHolder( mTopCard, PropertyValuesHolder.ofFloat("translationX", 0), PropertyValuesHolder.ofFloat("translationY", 0), PropertyValuesHolder.ofFloat( "rotation", (float) Math.toDegrees( mRandom.nextGaussian() * DISORDERED_MAX_ROTATION_RADIANS)), PropertyValuesHolder.ofFloat("pivotX", mTopCard.getWidth() / 2.f), PropertyValuesHolder.ofFloat("pivotY", mTopCard.getHeight() / 2.f)) .setDuration(250); animator.setInterpolator(new AccelerateInterpolator()); animator.start(); break; case MotionEvent.ACTION_POINTER_UP: pointerIndex = event.getActionIndex(); final int pointerId = event.getPointerId(pointerIndex); if (pointerId == mActivePointerId) { final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastTouchX = event.getX(newPointerIndex); mLastTouchY = event.getY(newPointerIndex); mActivePointerId = event.getPointerId(newPointerIndex); } break; } return true; }
/** @see View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent) */ @Override public boolean onTouch(View view, MotionEvent motionEvent) { if (!isSwipeEnabled()) { return false; } if (viewWidth < 2) { viewWidth = swipeListView.getWidth(); } switch (MotionEventCompat.getActionMasked(motionEvent)) { case MotionEvent.ACTION_DOWN: { if (paused && downPosition != ListView.INVALID_POSITION) { return false; } swipeCurrentAction = SwipeListView.SWIPE_ACTION_NONE; int childCount = swipeListView.getChildCount(); int[] listViewCoords = new int[2]; swipeListView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child; for (int i = 0; i < childCount; i++) { child = swipeListView.getChildAt(i); child.getHitRect(rect); int childPosition = swipeListView.getPositionForView(child); // dont allow swiping if this is on the header or footer or IGNORE_ITEM_VIEW_TYPE or // enabled is false on the adapter boolean allowSwipe = swipeListView.getAdapter().isEnabled(childPosition) && swipeListView.getAdapter().getItemViewType(childPosition) >= 0; if (allowSwipe && rect.contains(x, y)) { setParentView(child); setFrontView(child.findViewById(swipeFrontView)); downX = motionEvent.getRawX(); downPosition = childPosition; frontView.setClickable(!opened.get(downPosition)); frontView.setLongClickable(!opened.get(downPosition)); velocityTracker = VelocityTracker.obtain(); velocityTracker.addMovement(motionEvent); if (swipeBackView > 0) { setBackView(child.findViewById(swipeBackView)); } break; } } view.onTouchEvent(motionEvent); return true; } case MotionEvent.ACTION_UP: { if (velocityTracker == null || !swiping || downPosition == ListView.INVALID_POSITION) { break; } float deltaX = motionEvent.getRawX() - downX; velocityTracker.addMovement(motionEvent); velocityTracker.computeCurrentVelocity(1000); float velocityX = Math.abs(velocityTracker.getXVelocity()); if (!opened.get(downPosition)) { if (swipeMode == SwipeListView.SWIPE_MODE_LEFT && velocityTracker.getXVelocity() > 0) { velocityX = 0; } if (swipeMode == SwipeListView.SWIPE_MODE_RIGHT && velocityTracker.getXVelocity() < 0) { velocityX = 0; } } float velocityY = Math.abs(velocityTracker.getYVelocity()); boolean swap = false; boolean swapRight = false; if (minFlingVelocity <= velocityX && velocityX <= maxFlingVelocity && velocityY * 2 < velocityX) { swapRight = velocityTracker.getXVelocity() > 0; Log.d("SwipeListView", "swapRight: " + swapRight + " - swipingRight: " + swipingRight); if (swapRight != swipingRight && swipeActionLeft != swipeActionRight) { swap = false; } else if (opened.get(downPosition) && openedRight.get(downPosition) && swapRight) { swap = false; } else if (opened.get(downPosition) && !openedRight.get(downPosition) && !swapRight) { swap = false; } else { swap = true; } } else if (Math.abs(deltaX) > viewWidth / 2) { swap = true; swapRight = deltaX > 0; } generateAnimate(frontView, swap, swapRight, downPosition); if (swipeCurrentAction == SwipeListView.SWIPE_ACTION_CHOICE) { swapChoiceState(downPosition); } velocityTracker.recycle(); velocityTracker = null; downX = 0; // change clickable front view // if (swap) { // frontView.setClickable(opened.get(downPosition)); // frontView.setLongClickable(opened.get(downPosition)); // } swiping = false; break; } case MotionEvent.ACTION_MOVE: { if (velocityTracker == null || paused || downPosition == ListView.INVALID_POSITION) { break; } velocityTracker.addMovement(motionEvent); velocityTracker.computeCurrentVelocity(1000); float velocityX = Math.abs(velocityTracker.getXVelocity()); float velocityY = Math.abs(velocityTracker.getYVelocity()); float deltaX = motionEvent.getRawX() - downX; float deltaMode = Math.abs(deltaX); int swipeMode = this.swipeMode; int changeSwipeMode = swipeListView.changeSwipeMode(downPosition); if (changeSwipeMode >= 0) { swipeMode = changeSwipeMode; } if (swipeMode == SwipeListView.SWIPE_MODE_NONE) { deltaMode = 0; } else if (swipeMode != SwipeListView.SWIPE_MODE_BOTH) { if (opened.get(downPosition)) { if (swipeMode == SwipeListView.SWIPE_MODE_LEFT && deltaX < 0) { deltaMode = 0; } else if (swipeMode == SwipeListView.SWIPE_MODE_RIGHT && deltaX > 0) { deltaMode = 0; } } else { if (swipeMode == SwipeListView.SWIPE_MODE_LEFT && deltaX > 0) { deltaMode = 0; } else if (swipeMode == SwipeListView.SWIPE_MODE_RIGHT && deltaX < 0) { deltaMode = 0; } } } if (deltaMode > slop && swipeCurrentAction == SwipeListView.SWIPE_ACTION_NONE && velocityY < velocityX) { swiping = true; swipingRight = (deltaX > 0); Log.d("SwipeListView", "deltaX: " + deltaX + " - swipingRight: " + swipingRight); if (opened.get(downPosition)) { swipeListView.onStartClose(downPosition, swipingRight); swipeCurrentAction = SwipeListView.SWIPE_ACTION_REVEAL; } else { if (swipingRight && swipeActionRight == SwipeListView.SWIPE_ACTION_DISMISS) { swipeCurrentAction = SwipeListView.SWIPE_ACTION_DISMISS; } else if (!swipingRight && swipeActionLeft == SwipeListView.SWIPE_ACTION_DISMISS) { swipeCurrentAction = SwipeListView.SWIPE_ACTION_DISMISS; } else if (swipingRight && swipeActionRight == SwipeListView.SWIPE_ACTION_CHOICE) { swipeCurrentAction = SwipeListView.SWIPE_ACTION_CHOICE; } else if (!swipingRight && swipeActionLeft == SwipeListView.SWIPE_ACTION_CHOICE) { swipeCurrentAction = SwipeListView.SWIPE_ACTION_CHOICE; } else { swipeCurrentAction = SwipeListView.SWIPE_ACTION_REVEAL; } swipeListView.onStartOpen(downPosition, swipeCurrentAction, swipingRight); } swipeListView.requestDisallowInterceptTouchEvent(true); MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); cancelEvent.setAction( MotionEvent.ACTION_CANCEL | (MotionEventCompat.getActionIndex(motionEvent) << MotionEventCompat.ACTION_POINTER_INDEX_SHIFT)); swipeListView.onTouchEvent(cancelEvent); if (swipeCurrentAction == SwipeListView.SWIPE_ACTION_CHOICE) { backView.setVisibility(View.GONE); } } if (swiping && downPosition != ListView.INVALID_POSITION) { if (opened.get(downPosition)) { deltaX += openedRight.get(downPosition) ? viewWidth - rightOffset : -viewWidth + leftOffset; } move(deltaX); return true; } break; } } return false; }