How to Implement the interaction between two ViewPager and achieve the interaction between viewpager
I have written an article about how to implement zaker5.0's guiding interface. For details, see view interaction effect (modify viewpager implementation) of zaker's latest guide interface ), this article is a continuation of the article.
Let's take a look at the final effect:
Linkage ViewPager means that when a viewpager slides, another ViewPager also slides, and the two are synchronized.
If ViewPager has a callback interface for moving distance, this is easy to do. Unfortunately, there is no callback interface. There is only one OnPageChangeListener. I tried using onPageScrolled (int position, float positionOffset, int positionOffsetPixels.
Then only custom ViewPager is available.
I directly extract the source code of ViewPager to v4 and remove unnecessary things until the class cannot be found,
In addition to ViewPager, you also need to take out the relevant PagerAdapter class. Otherwise, ViewPager uses its own and adapter uses v4, which may cause problems.
Add a private variable to ViewPager to achieve interaction.mFollowViewPager
(Add the set Method of the variable at the same time ):
private ViewPager mFollowViewPager;public void setFlolwViewPager(ViewPager page){mFollowViewPager = page;}
My idea is to call
mFollowViewPager
ScrollTo method. So where can I add it? After carefully tracking the ViewPager behavior, I found that when the finger is not released, the mongomdrag method handles the relevant movement, he calls his own scrollTo to implement its own translation. Therefore, we only need to add the following code in the mongomdrag method:
//add by jcodecraeerfinal float pageOffset = scrollX / width;if(mFollowViewPager!=null){mFollowViewPager.scrollTo( (int)(pageOffset*mFollowViewPager.getWidth()), mFollowViewPager.getScrollY());}
Note that it is not how far the main ViewPager is moved,mFollowViewPager
How far is the movement, because the width of the two ViewPager may be different, so you need to convert it. In the code abovefinal float pageOffset = scrollX / width;
pageOffset
Only the obtained values are converted.
ModifiedperformDrag
As follows:
private boolean performDrag(float x) { boolean needsInvalidate = false; final float deltaX = mLastMotionX - x; mLastMotionX = x; float oldScrollX = getScrollX(); float scrollX = oldScrollX + deltaX; final int width = getWidth(); float leftBound = width * mFirstOffset; float rightBound = width * mLastOffset; boolean leftAbsolute = true; boolean rightAbsolute = true; final ItemInfo firstItem = mItems.get(0); final ItemInfo lastItem = mItems.get(mItems.size() - 1); if (firstItem.position != 0) { leftAbsolute = false; leftBound = firstItem.offset * width; } if (lastItem.position != mAdapter.getCount() - 1) { rightAbsolute = false; rightBound = lastItem.offset * width; } if (scrollX < leftBound) { if (leftAbsolute) { float over = leftBound - scrollX; needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width); } scrollX = leftBound; } else if (scrollX > rightBound) { if (rightAbsolute) { float over = scrollX - rightBound; needsInvalidate = mRightEdge.onPull(Math.abs(over) / width); } scrollX = rightBound; } // Don't lose the rounded component mLastMotionX += scrollX - (int) scrollX; scrollTo((int) scrollX, getScrollY()); pageScrolled((int) scrollX); //add by jcodecraeerfinal float pageOffset = scrollX / width;if(mFollowViewPager!=null){mFollowViewPager.scrollTo( (int)(pageOffset*mFollowViewPager.getWidth()), mFollowViewPager.getScrollY());} return needsInvalidate; }
It is not enough to translate the processed finger without leaving the screen. When the finger is released, ViewPager will continue for a certain distance. Therefore, mFollowViewPager should also be moved, whether the finger is released in case MotionEvent. what is processed in ACTION_UP?
Find the relevant code:
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 = getWidth(); 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); int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, totalDelta); setCurrentItemInternal(nextPage, true, true, initialVelocity); mActivePointerId = INVALID_POINTER; endDrag(); needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); }
We can see that
setCurrentItemInternal
Medium
Called
ScrollToItem (item, smoothScroll, velocity, dispatchSelected. That is to say,mFollowViewPager
If we call
setCurrentItemInternal
So that he can also move. Based on this idea, we will rewrite the code segment of case MotionEvent. ACTION_UP:
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 = getWidth(); 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); int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, totalDelta); setCurrentItemInternal(nextPage, true, true, initialVelocity); //add by jcodecraeer if(mFollowViewPager!=null){ mFollowViewPager.setCurrentItemInternal(nextPage, true, true, initialVelocity); } mActivePointerId = INVALID_POINTER; endDrag(); needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); }
So far, we have completed all the modifications, but we have not actually changed a few lines.
So how can we use the modified ViewPager in the activity to link two viewpagers? Assume that one is mViewPager and the other is mFollowViewPager.mFollowViewPager
WithmViewPager
Dynamic, then:
mPager.setFollowViewPager(mFollowViewPager);
Note that in the demo I will give next, I blocked
followViewPager
To overwrite the main ViewPager in
Above followViewPager, which is consistent with the effect I want to achieve. If you wantfollowViewPager
In turn, the main ViewPager can also be moved and called in turn:
MFollowViewPager. setFollowViewPager (mPager );
However, I am not sure whether this two-way call will cause problems, because I have not strictly consideredmFollowViewPager
Some state changes (such as related variables) that should be caused by moving the variable ). You can give it a try and then make improvements.
Source code: http://jcodecraeer.com/a/opensource/2014/1031/1885.html
Add by jcodecraeer labels are used for ViewPager Transformation (excluding unnecessary code to delete)
There are only two ViewPager items, and the two items have operations such as networking and input boxes. How can we achieve circular sliding?
New Employee reports. view the original post>
How to Implement nested ViewPager
Grace, but you 'd better rewrite the title above ViewPager. More beautiful