@Override protected void dispatchDraw(Canvas canvas) { if (mPageCount < 1) { return; } boolean needsInvalidate = false; if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { mFlipDistance = mScroller.getCurrY(); needsInvalidate = true; } if (mIsFlipping || !mScroller.isFinished() || mPeakAnim != null) { drawPreviousHalf(canvas); drawNextHalf(canvas); drawFlippingHalf(canvas); } else { endScroll(); final int currentPage = getCurrentPageFloor(); if (mCurrentPage != currentPage) { postRemoveView(getChildAt(0)); } final View v = viewForPage(currentPage); if (mCurrentPage != currentPage) { postAddView(v); postFlippedToPage(currentPage); mCurrentPage = currentPage; mCurrentPageId = mAdapter.getItemId(mCurrentPage); } setDrawWithLayer(v, false); v.draw(canvas); } // if overflip is GLOW mode and the edge effects needed drawing, make // sure to invalidate needsInvalidate |= mOverFlipper.draw(canvas); if (needsInvalidate) { // always invalidate whole screen as it is needed 99% of the time. // This is because of the shadows and shines put on the non-flipping // pages invalidate(); } }
@Override protected void dispatchDraw(Canvas canvas) { if (mPageCount < 1) { return; } if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { setFlipDistance(mScroller.getCurrY()); } if (mIsFlipping || !mScroller.isFinished() || mPeakAnim != null) { showAllPages(); drawPreviousHalf(canvas); drawNextHalf(canvas); drawFlippingHalf(canvas); } else { endScroll(); setDrawWithLayer(mCurrentPage.v, false); hideOtherPages(mCurrentPage); drawChild(canvas, mCurrentPage.v, 0); // dispatch listener event now that we have "landed" on a page. // TODO not the prettiest to have this with the drawing logic, // should change. if (mLastDispatchedPageEventIndex != mCurrentPageIndex) { mLastDispatchedPageEventIndex = mCurrentPageIndex; postFlippedToPage(mCurrentPageIndex); } } // if overflip is GLOW mode and the edge effects needed drawing, make // sure to invalidate if (mOverFlipper.draw(canvas)) { // always invalidate whole screen as it is needed 99% of the time. // This is because of the shadows and shines put on the non-flipping // pages invalidate(); } }
@Override public boolean onTouchEvent(MotionEvent ev) { if (!mIsFlippingEnabled) { return false; } if (mPageCount < 1) { return false; } if (!mIsFlipping && !mLastTouchAllowed) { return false; } final int action = ev.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE) { mLastTouchAllowed = false; } else { mLastTouchAllowed = true; } trackVelocity(ev); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // start flipping immediately if interrupting some sort of animation if (endScroll() || endPeak()) { mIsFlipping = true; } // Remember where the motion event started mLastX = ev.getX(); mLastY = ev.getY(); mActivePointerId = MotionEventCompat.getPointerId(ev, 0); break; case MotionEvent.ACTION_MOVE: if (!mIsFlipping) { final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); if (pointerIndex == -1) { mActivePointerId = INVALID_POINTER; break; } final float x = MotionEventCompat.getX(ev, pointerIndex); final float xDiff = Math.abs(x - mLastX); final float y = MotionEventCompat.getY(ev, pointerIndex); final float yDiff = Math.abs(y - mLastY); if ((mIsFlippingVertically && yDiff > mTouchSlop && yDiff > xDiff) || (!mIsFlippingVertically && xDiff > mTouchSlop && xDiff > yDiff)) { mIsFlipping = true; mLastX = x; mLastY = y; } } if (mIsFlipping) { // Scroll to follow the motion event final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); if (activePointerIndex == -1) { mActivePointerId = INVALID_POINTER; break; } final float x = MotionEventCompat.getX(ev, activePointerIndex); final float deltaX = mLastX - x; final float y = MotionEventCompat.getY(ev, activePointerIndex); final float deltaY = mLastY - y; mLastX = x; mLastY = y; float deltaFlipDistance = 0; if (mIsFlippingVertically) { deltaFlipDistance = deltaY; } else { deltaFlipDistance = deltaX; } deltaFlipDistance /= ((isFlippingVertically() ? getHeight() : getWidth()) / FLIP_DISTANCE_PER_PAGE); setFlipDistance(mFlipDistance + deltaFlipDistance); final int minFlipDistance = 0; final int maxFlipDistance = (mPageCount - 1) * FLIP_DISTANCE_PER_PAGE; final boolean isOverFlipping = mFlipDistance < minFlipDistance || mFlipDistance > maxFlipDistance; if (isOverFlipping) { mIsOverFlipping = true; setFlipDistance( mOverFlipper.calculate(mFlipDistance, minFlipDistance, maxFlipDistance)); if (mOnOverFlipListener != null) { float overFlip = mOverFlipper.getTotalOverFlip(); mOnOverFlipListener.onOverFlip( this, mOverFlipMode, overFlip < 0, Math.abs(overFlip), FLIP_DISTANCE_PER_PAGE); } } else if (mIsOverFlipping) { mIsOverFlipping = false; if (mOnOverFlipListener != null) { // TODO in the future should only notify flip distance 0 // on the correct edge (previous/next) mOnOverFlipListener.onOverFlip(this, mOverFlipMode, false, 0, FLIP_DISTANCE_PER_PAGE); mOnOverFlipListener.onOverFlip(this, mOverFlipMode, true, 0, FLIP_DISTANCE_PER_PAGE); } } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsFlipping) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int velocity = 0; if (isFlippingVertically()) { velocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker, mActivePointerId); } else { velocity = (int) VelocityTrackerCompat.getXVelocity(velocityTracker, mActivePointerId); } smoothFlipTo(getNextPage(velocity)); mActivePointerId = INVALID_POINTER; endFlip(); mOverFlipper.overFlipEnded(); } break; case MotionEventCompat.ACTION_POINTER_DOWN: { final int index = MotionEventCompat.getActionIndex(ev); final float x = MotionEventCompat.getX(ev, index); final float y = MotionEventCompat.getY(ev, index); mLastX = x; mLastY = y; mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; } case MotionEventCompat.ACTION_POINTER_UP: onSecondaryPointerUp(ev); final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, index); final float y = MotionEventCompat.getY(ev, index); mLastX = x; mLastY = y; break; } if (mActivePointerId == INVALID_POINTER) { mLastTouchAllowed = false; } return true; }