@myron-lee
2017-03-22T12:28:21.000000Z
字数 8798
阅读 2769
Blog
这种轮播效果多应用于展示电影海报,但是效果并不好,有些没有手势动画,更加没有fling效果。我将ViewPager的源码拷贝出来,做了修改,实现了这两个效果。

private void scrollToItem(int item, boolean smoothScroll, int velocity,boolean dispatchSelected) {final ItemInfo curInfo = infoForPosition(item);int destX = 0;if (curInfo != null) {final int width = getClientWidth();destX = (int) (width * Math.max(mFirstOffset,Math.min(curInfo.offset, mLastOffset)));}//我的修改if (item != 0 && item != mAdapter.getCount() - 2 && item != mAdapter.getCount() - 1) {destX = destX - itemScrollOffset;}/*if (item == mAdapter.getCount() - 1) {destX = destX + itemScrollOffset;} else {destX = destX - itemScrollOffset;}*/if (smoothScroll) {smoothScrollTo(destX, 0, velocity);if (dispatchSelected) {dispatchOnPageSelected(item);}} else {if (dispatchSelected) {dispatchOnPageSelected(item);}completeScroll(false);scrollTo(destX, 0);pageScrolled(destX);}}
//这个逻辑比较复杂,总的来说是通过第一个page的相对窗口的偏移去计算当前可见的三个page的缩放比例,这个计算过程比较复杂//这跟你的page占屏幕宽度的比例,后台page缩放多少有关。viewPager.addOnPageChangeListener(new MultiCardViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {// Log.e("", position + " " + positionOffset);if (position == 0 && positionOffset == 0) {return;}View leftPage = viewPager.findViewWithTag(position);View middlePage = viewPager.findViewWithTag(position + 1);View rightPage = viewPager.findViewWithTag(position + 2);if (position == 0) {if (middlePage != null) {float scale = 1 - positionOffset * frontPageLeftOffset * frontBackScaleDelta;setScale(middlePage, scale);setDim(middlePage, scale);}if (rightPage != null) {float scale = backgroundPageScale + positionOffset * frontPageLeftOffset * frontBackScaleDelta;setScale(rightPage, scale);setDim(rightPage, scale);}return;}if (leftPage != null) {if (positionOffset < pageGoToBackgroundOffsetThreshold) {//become smallerfloat scale = 1 - (positionOffset + frontPageLeftOffset) * frontBackScaleDelta;setScale(leftPage, scale);setDim(leftPage, scale);} else {//stay stillsetScale(leftPage, backgroundPageScale);setDim(leftPage, backgroundPageScale);}}if (middlePage != null) {if (positionOffset < pageGoToBackgroundOffsetThreshold) {//become biggerfloat scale = backgroundPageScale + (positionOffset + frontPageLeftOffset) * frontBackScaleDelta;setScale(middlePage, scale);setDim(middlePage, scale);} else {//become smallerfloat scale = 1 - (positionOffset - pageGoToBackgroundOffsetThreshold) * frontBackScaleDelta;setScale(middlePage, scale);setDim(middlePage, scale);}}if (rightPage != null) {if (positionOffset < pageGoToBackgroundOffsetThreshold) {//stay stillsetScale(rightPage, backgroundPageScale);setDim(rightPage, backgroundPageScale);} else {//become biggerfloat scale = backgroundPageScale + (positionOffset - pageGoToBackgroundOffsetThreshold) * frontBackScaleDelta;setScale(rightPage, scale);setDim(rightPage, scale);}}}@Overridepublic void onPageSelected(int position) {}@Overridepublic void onPageScrollStateChanged(int state) {}});
@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (mFakeDragging) {// A fake drag is in progress already, ignore this real one// but still eat the touch events.// (It is likely that the user is multi-touching the screen.)return true;}if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {// Don't handle edge touches immediately -- they may actually belong to one of our// descendants.return false;}if (mAdapter == null || mAdapter.getCount() == 0) {// Nothing to present or scroll; nothing to touch.return false;}if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(ev);final int action = ev.getAction();boolean needsInvalidate = false;switch (action & MotionEventCompat.ACTION_MASK) {case MotionEvent.ACTION_DOWN: {mScroller.abortAnimation();mPopulatePending = false;populate();// Remember where the motion event startedmLastMotionX = mInitialMotionX = ev.getX();mLastMotionY = mInitialMotionY = ev.getY();mActivePointerId = MotionEventCompat.getPointerId(ev, 0);break;}case MotionEvent.ACTION_MOVE:if (!mIsBeingDragged) {final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);final float x = MotionEventCompat.getX(ev, pointerIndex);final float xDiff = Math.abs(x - mLastMotionX);final float y = MotionEventCompat.getY(ev, pointerIndex);final float yDiff = Math.abs(y - mLastMotionY);if (DEBUG)Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);if (xDiff > mTouchSlop && xDiff > yDiff) {if (DEBUG) Log.v(TAG, "Starting drag!");mIsBeingDragged = true;requestParentDisallowInterceptTouchEvent(true);mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :mInitialMotionX - mTouchSlop;mLastMotionY = y;setScrollState(SCROLL_STATE_DRAGGING);setScrollingCacheEnabled(true);// Disallow Parent Intercept, just in caseViewParent parent = getParent();if (parent != null) {parent.requestDisallowInterceptTouchEvent(true);}}}// Not else! Note that mIsBeingDragged can be set above.if (mIsBeingDragged) {// Scroll to follow the motion eventfinal int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);final float x = MotionEventCompat.getX(ev, activePointerIndex);needsInvalidate |= performDrag(x);}break;case MotionEvent.ACTION_UP:if (mIsBeingDragged) {final VelocityTracker velocityTracker = mVelocityTracker;velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(velocityTracker, mActivePointerId);mPopulatePending = true;final int width = getClientWidth();final int scrollX = getScrollX();final ItemInfo ii = infoForCurrentScrollPosition();final int currentPage = ii.position;final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;final int activePointerIndex =MotionEventCompat.findPointerIndex(ev, mActivePointerId);final float x = MotionEventCompat.getX(ev, activePointerIndex);final int totalDelta = (int) (x - mInitialMotionX);//我的修改if (Math.abs(initialVelocity) < 4000) {int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,totalDelta);setCurrentItemInternal(nextPage, true, true, initialVelocity);} else {fling = true;// Log.e("Velocity", initialVelocity + "");mScroller.fling(getScrollX(), getScrollY(), -initialVelocity, 0, minScrollX, maxScrollX, getScrollY(), getScrollY());}mActivePointerId = INVALID_POINTER;endDrag();needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();}break;case MotionEvent.ACTION_CANCEL:if (mIsBeingDragged) {scrollToItem(mCurItem, true, 0, false);mActivePointerId = INVALID_POINTER;endDrag();needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();}break;case MotionEventCompat.ACTION_POINTER_DOWN: {final int index = MotionEventCompat.getActionIndex(ev);final float x = MotionEventCompat.getX(ev, index);mLastMotionX = x;mActivePointerId = MotionEventCompat.getPointerId(ev, index);break;}case MotionEventCompat.ACTION_POINTER_UP:onSecondaryPointerUp(ev);mLastMotionX = MotionEventCompat.getX(ev,MotionEventCompat.findPointerIndex(ev, mActivePointerId));break;}if (needsInvalidate) {ViewCompat.postInvalidateOnAnimation(this);}return true;}@Overridepublic void computeScroll() {if (!myScroller.isFinished() && myScroller.computeScrollOffset()) {int oldX = getScrollX();int oldY = getScrollY();int x = myScroller.getCurrX();int y = myScroller.getCurrY();if (oldX != x || oldY != y) {scrollTo(x, y);if (!pageScrolled(x)) {myScroller.abortAnimation();scrollTo(0, y);}}// Keep on drawing until the animation has finished.ViewCompat.postInvalidateOnAnimation(this);return;}if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {int oldX = getScrollX();int oldY = getScrollY();int x = mScroller.getCurrX();int y = mScroller.getCurrY();if (oldX != x || oldY != y) {scrollTo(x, y);if (!pageScrolled(x)) {mScroller.abortAnimation();scrollTo(0, y);}}// Keep on drawing until the animation has finished.ViewCompat.postInvalidateOnAnimation(this);return;}//我的修改if (fling) {ItemInfo curInfo = infoForCurrentScrollPosition();if (getScrollX() > (curInfo.offset + 0.225) * getWidth()) {if (curInfo.position + 1 < mAdapter.getCount()) {curInfo = infoForPosition(curInfo.position + 1);}}// final ItemInfo curInfo = infoForPosition(item);int destX = 0;if (curInfo != null) {final int width = getClientWidth();destX = (int) (width * Math.max(mFirstOffset,Math.min(curInfo.offset, mLastOffset)));}if (curInfo.position != 0 && curInfo.position != mAdapter.getCount() - 2 && curInfo.position != mAdapter.getCount() - 1) {destX = destX - itemScrollOffset;}// smoothScrollTo(destX, 0, 100);mScroller.startScroll(getScrollX(), getScrollY(), destX - getScrollX(), 0, 600);ViewCompat.postInvalidateOnAnimation(this);dispatchOnPageSelected(curInfo.position);fling = false;return;}// scrollToItem(itemInfo.position, true, 100, true);// setCurrentItemInternal(itemInfo.position, false, true, 100);// setCurrentItem(itemInfo.position, true);// fling = false;// Done with scroll, clean up state.completeScroll(true);}