Cómo realizar el vínculo entre dos ViewPagers
Si ViewPager tuviera una interfaz de devolución de llamada sobre la distancia de movimiento, eso no sería un problema. Desafortunadamente, no la hay. Intenté usar onPageScrolled(int
. posición, flotar en el parámetro OnPageChangeListener positionOffset, int positionOffsetPixels), pero falló.
Entonces es solo un ViewPager personalizado.
Simplemente sacaré el código fuente de ViewPager rushing v4 y eliminaré algunas cosas innecesarias hasta que ya no pueda encontrar esta clase.
Además de eliminar ViewPager, también debe eliminar la clase PagerAdapter relacionada; de lo contrario, ViewPager usa la suya propia y el adaptador usa la suya propia y v4, lo que puede causar problemas.
Para implementar el enlace, agregue una variable privada mFollowViewPager en ViewPager (también agregue el método set de la variable):
private ViewPager mFollowViewPager;
public void setFlolwViewPager(página ViewPager){
mFollowViewPager = page;
}
Mi idea es llamar al método scrollTo de mFollowViewPager en el código relacionado con el desplazamiento actual de ViewPager. método.
Entonces, ¿cuál es el mejor lugar para agregarlo? Después de rastrear cuidadosamente el comportamiento de ViewPager, descubrí que cuando no se suelta el dedo, el método formDrag manejará el movimiento relacionado y llamará a su propio método scrollTo para implementar su propia traducción, por lo que solo necesitamos agregar el siguiente código. en el método formDrag: //agregar por jcodecraeer
final float pageOffset = scrollX / ancho;
if(mFollowViewPager!=null){
mFollowViewPager.scrollTo ( (int)( pageOffset*mFollowViewPager.getWidth()), mFollowViewPager.getScrollY());
}
Tenga en cuenta que el ViewPager principal no se mueve la misma distancia que el mFollowViewPager . Dado que los anchos de los dos ViewPagers pueden ser diferentes, es necesario convertirlos. El pageOffset flotante final = scrollX / width;pageOffset
en el código anterior es el valor obtenido después de la conversión.
El performDrag reescrito es el siguiente:
private boolean performDrag(float x) {
boolean needInvalidate = false
final float; deltaX = mLastMotionX - x;
mLastMotionX = x;
flotar oldScrollX = getScrollX()
flotar scrollX = oldScrollX + deltaX; p>final int width = getWidth();
float leftBound = ancho * mFirstOffset;
float rightBound = ancho * mLastOffset;
boolean leftAbsolute = true;
boolean rightAbsolute = true;
Información del elemento final firstItem = mItems.get(0);
Info del elemento final lastItem = mItems.get(mItems.size( ) - 1);
if (firstItem.position ! = 0) {
leftAbsolute = false;
leftBound = firstItem.offset * ancho;
}
if (lastItem.position != mAdapter.getCount() - 1) {
rightAbsolute = false;
rightBound = lastItem. desplazamiento * ancho;
}
if (scrollX < leftBound) {
if (leftAbsolute) {
flotar sobre = leftBound - scrollX;
needsInvalidate = mLeftEdge.onPull(Math.abs(sobre) / ancho);
}
}
scrollX = leftBound;
} else if (scrollX > rightBound) {
if (rightAbsolute) {
float over = scrollX - rightBound;
needsInvalidate = mRightEdge.onPull(Math. abs(over) / ancho;
}
}
scrollX = rightBound;
}
//No pierdas el componente circular
mLastMotionX += scrollX - (int) scrollX;
scrollTo((int) scrollX, getScrollY( )) ;
pageScrolled((int) scrollX);
//dad por jcodecraeer
pageOffset flotante final = scrollX / ancho;
if(mFollowViewPager!=scrollTo( (int)(pageOffset*mFollowViewPager.getWidth()), mFollowViewPager.getScrollY());
}
return needInvalidate;
}
No es suficiente manejar la traducción del dedo antes de que salga de la pantalla. Después de soltar el dedo, ViewPager continuará moviéndose a una cierta distancia. , por lo que mFollowViewPager también debería seguir el movimiento. Pensemos en ello, ¿deberíamos manejar MotionEvent.ACTION_UP cuando se suelta el dedo?
Encontramos el código relevante:
case MotionEvent. ACTION_UP:
if (mIsBeingDragged) {
Final VelocityTracker velocidadTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int inicialVelocity = (int) VelocityTrackerCompat .getXVelocity(
velocityTracker, mActivePointerId);
mPopulatePending = true;
final int width = getWidth(); p>
final int scrollX = getScrollX();
final ItemInfo ii = infoForCurrentScrollPosition();
final int currentPage = ii .position
final float pageOffset = ((( float) scrollX / ancho) - 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
); ActivePointerId = INVALID_POINTER;
endDrag();
needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
}
Como puede verse, setCurrentIte
mInternal llama a scrollToItem(item, smoothScroll, speed, despachoSelected para lograr el efecto de continuar desplazandose después de soltar el dedo); En otras palabras, para mFollowViewPager, si llamamos a setCurrentItemInternal al mismo tiempo, podemos dejar que continúe moviéndose. En esta línea, reescribimos case
fragmento MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
Final VelocityTracker speedTracker = mVelocityTracker ;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int inicialVelocity = (int) VelocityTrackerCompat.getXVelocity(