viewpager support studio showing practice pageradapter not example best android animation android-viewpager

android - support - Cambie la duración de la animación de ViewPager cuando se desliza programáticamente



viewpager in fragment (5)

Estoy cambiando la diapositiva con

viewPager.setCurrentItem(index++, true);

Pero cambia a rápido. ¿Hay alguna manera de configurar manualmente la velocidad de la animación?

Busqué y solo encontré a alguien preguntando lo mismo en todas partes (además de StackOverflow, tal vez tenga suerte aquí :)), sin respuestas.

Me gusta:

https://groups.google.com/group/android-developers/browse_thread/thread/a13405c0b5833893?fwc=1

Gracias por adelantado.


Aquí está mi código usado en Librera Reader

public class MyViewPager extends ViewPager { public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); initMyScroller(); } private void initMyScroller() { try { Class<?> viewpager = ViewPager.class; Field scroller = viewpager.getDeclaredField("mScroller"); scroller.setAccessible(true); scroller.set(this, new MyScroller(getContext())); // my liner scroller Field mFlingDistance = viewpager.getDeclaredField("mFlingDistance"); mFlingDistance.setAccessible(true); mFlingDistance.set(this, Dips.DP_10);//10 dip Field mMinimumVelocity = viewpager.getDeclaredField("mMinimumVelocity"); mMinimumVelocity.setAccessible(true); mMinimumVelocity.set(this, 0); //0 velocity } catch (Exception e) { LOG.e(e); } } public class MyScroller extends Scroller { public MyScroller(Context context) { super(context, new LinearInterpolator()); // my LinearInterpolator } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { super.startScroll(startX, startY, dx, dy, 175);//175 duration } } }


Encontré una mejor solución, basada en la respuesta de @df778899 y la API de Android ValueAnimator . Funciona bien sin reflexión y es muy flexible. Además, no es necesario crear ViewPager personalizado y colocarlo en el paquete android.support.v4.view. Aquí hay un ejemplo:

private void animatePagerTransition(final boolean forward) { ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth()); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { viewPager.endFakeDrag(); } @Override public void onAnimationCancel(Animator animation) { viewPager.endFakeDrag(); } @Override public void onAnimationRepeat(Animator animation) { } }); animator.setInterpolator(new AccelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { private int oldDragPosition = 0; @Override public void onAnimationUpdate(ValueAnimator animation) { int dragPosition = (Integer) animation.getAnimatedValue(); int dragOffset = dragPosition - oldDragPosition; oldDragPosition = dragPosition; viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1)); } }); animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS); viewPager.beginFakeDrag(); animator.start(); }

ACTUALIZAR:

Acabo de comprobar si esta solución se puede utilizar para deslizar varias páginas a la vez (por ejemplo, si la primera página debe mostrarse después de la última). Este es un código ligeramente modificado para manejar el conteo de páginas especificado:

private int oldDragPosition = 0; private void animatePagerTransition(final boolean forward, int pageCount) { // if previous animation have not finished we can get exception if (pagerAnimation != null) { pagerAnimation.cancel(); } pagerAnimation = getPagerTransitionAnimation(forward, pageCount); if (viewPager.beginFakeDrag()) { // checking that started drag correctly pagerAnimation.start(); } } private Animator getPagerTransitionAnimation(final boolean forward, int pageCount) { ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth() - 1); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { viewPager.endFakeDrag(); } @Override public void onAnimationCancel(Animator animation) { viewPager.endFakeDrag(); } @Override public void onAnimationRepeat(Animator animation) { viewPager.endFakeDrag(); oldDragPosition = 0; viewPager.beginFakeDrag(); } }); animator.setInterpolator(new AccelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int dragPosition = (Integer) animation.getAnimatedValue(); int dragOffset = dragPosition - oldDragPosition; oldDragPosition = dragPosition; viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1)); } }); animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS / pageCount); // remove divider if you want to make each transition have the same speed as single page transition animator.setRepeatCount(pageCount); return animator; }


He querido hacerlo yo mismo y he logrado una solución (utilizando la reflexión, sin embargo). Todavía no lo he probado, pero debería funcionar o necesitar modificaciones mínimas. Probado en Galaxy Nexus JB 4.2.1. Necesita usar ViewPagerCustomDuration en su XML en lugar de ViewPager , y luego puede hacer esto:

ViewPagerCustomDuration vp = (ViewPagerCustomDuration) findViewById(R.id.myPager); vp.setScrollDurationFactor(2); // make the animation twice as slow

ViewPagerCustomDuration.java :

import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.animation.Interpolator; import java.lang.reflect.Field; public class ViewPagerCustomDuration extends ViewPager { public ViewPagerCustomDuration(Context context) { super(context); postInitViewPager(); } public ViewPagerCustomDuration(Context context, AttributeSet attrs) { super(context, attrs); postInitViewPager(); } private ScrollerCustomDuration mScroller = null; /** * Override the Scroller instance with our own class so we can change the * duration */ private void postInitViewPager() { try { Field scroller = ViewPager.class.getDeclaredField("mScroller"); scroller.setAccessible(true); Field interpolator = ViewPager.class.getDeclaredField("sInterpolator"); interpolator.setAccessible(true); mScroller = new ScrollerCustomDuration(getContext(), (Interpolator) interpolator.get(null)); scroller.set(this, mScroller); } catch (Exception e) { } } /** * Set the factor by which the duration will change */ public void setScrollDurationFactor(double scrollFactor) { mScroller.setScrollDurationFactor(scrollFactor); } }

ScrollerCustomDuration.java :

import android.annotation.SuppressLint; import android.content.Context; import android.view.animation.Interpolator; import android.widget.Scroller; public class ScrollerCustomDuration extends Scroller { private double mScrollFactor = 1; public ScrollerCustomDuration(Context context) { super(context); } public ScrollerCustomDuration(Context context, Interpolator interpolator) { super(context, interpolator); } @SuppressLint("NewApi") public ScrollerCustomDuration(Context context, Interpolator interpolator, boolean flywheel) { super(context, interpolator, flywheel); } /** * Set the factor by which the duration will change */ public void setScrollDurationFactor(double scrollFactor) { mScrollFactor = scrollFactor; } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor)); } }

¡Espero que esto ayude a alguien!


Una mejor solución es simplemente acceder a los campos privados creando la clase en el paquete de soporte. EDITAR Esto está vinculado a MAX_SETTLE_DURATION de 600 ms, establecido por la clase ViewPager .

package android.support.v4.view; import android.content.Context; import android.util.AttributeSet; public class SlowViewPager extends ViewPager { // The speed of the scroll used by setCurrentItem() private static final int VELOCITY = 200; public SlowViewPager(Context context) { super(context); } public SlowViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { setCurrentItemInternal(item, smoothScroll, always, VELOCITY); } }

Por supuesto, puede agregar un atributo personalizado para que pueda establecerse a través de XML.


public class PresentationViewPager extends ViewPager { public static final int DEFAULT_SCROLL_DURATION = 250; public static final int PRESENTATION_MODE_SCROLL_DURATION = 1000; public PresentationViewPager (Context context) { super(context); } public PresentationViewPager (Context context, AttributeSet attrs) { super(context, attrs); } public void setDurationScroll(int millis) { try { Class<?> viewpager = ViewPager.class; Field scroller = viewpager.getDeclaredField("mScroller"); scroller.setAccessible(true); scroller.set(this, new OwnScroller(getContext(), millis)); } catch (Exception e) { e.printStackTrace(); } } public class OwnScroller extends Scroller { private int durationScrollMillis = 1; public OwnScroller(Context context, int durationScroll) { super(context, new DecelerateInterpolator()); this.durationScrollMillis = durationScroll; } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { super.startScroll(startX, startY, dx, dy, durationScrollMillis); } } }