Change ViewPager animation duration when sliding programmatically

前端 未结 7 1085
清酒与你
清酒与你 2020-11-28 20:45

I\'m changing slide with the following code:

viewPager.setCurrentItem(index++, true);

But it changes too fast. Is there a way to set manual

相关标签:
7条回答
  • 2020-11-28 20:47

    Here is my code used in 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
            }
        }
    
     }
    
    0 讨论(0)
  • 2020-11-28 20:48

    I've wanted to do myself and have achieved a solution (using reflection, however). I haven't tested it yet but it should work or need minimal modification. Tested on Galaxy Nexus JB 4.2.1. You need to use a ViewPagerCustomDuration in your XML instead of ViewPager, and then you can do this:

    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));
        }
    
    }
    

    Hope this helps someone!

    0 讨论(0)
  • 2020-11-28 20:49
     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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 20:51

    Better solution is to simply access the private fields by creating the class in the support package. EDIT This is bound to the MAX_SETTLE_DURATION of 600ms, set by the ViewPagerclass.

    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);
        }
    
    }
    

    You can, of course, then add a custom attribute so this can be set via XML.

    0 讨论(0)
  • 2020-11-28 20:59

    After wasting my whole day I found a solution set offscreenPageLimit to total no. of the page.

    In order to keep a constant length ViewPager scrolls smooth, setOffScreenLimit(page.length) will keep all the views in memory. However, this poses a problem for any animations that involves calling View.requestLayout function (e.g. any animation that involves making changes to the margin or bounds). It makes them really slow (as per Romain Guy) because the all of the views that's in memory will be invalidated as well. So I tried a few different ways to make things smooth but overriding requestLayout and other invalidate methods will cause many other problems.

    A good compromise is to dynamically modify the off screen limit so that most of the scrolls between pages will be very smooth while making sure that all of the in page animations smooth by removing the views when the user. This works really well when you only have 1 or 2 views that will have to make other views off memory.

    ***Use this when no any solution works because by setting offeset limit u will load all the fragments at the same time

    0 讨论(0)
  • 2020-11-28 21:01

    I used Cicero Moura's version to make a Kotlin class that still works perfectly as of Android 10.

    import android.content.Context
    import android.util.AttributeSet
    import android.view.MotionEvent
    import android.view.animation.DecelerateInterpolator
    import android.widget.Scroller
    import androidx.viewpager.widget.ViewPager
    
    class CustomViewPager(context: Context, attrs: AttributeSet) :
            ViewPager(context, attrs) {
    
    
        private companion object {
            const val DEFAULT_SPEED = 1000
        }
    
        init {
            setScrollerSpeed(DEFAULT_SPEED)
        }
    
        var scrollDuration = DEFAULT_SPEED
            set(millis) {
                setScrollerSpeed(millis)
            }
    
        private fun setScrollerSpeed(millis: Int) {
            try {
                ViewPager::class.java.getDeclaredField("mScroller")
                        .apply {
                            isAccessible = true
                            set(this@CustomViewPager, OwnScroller(millis))
                        }
    
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    
        inner class OwnScroller(private val durationScrollMillis: Int) : Scroller(context, AccelerateDecelerateInterpolator()) {
            override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int, duration: Int) {
                super.startScroll(startX, startY, dx, dy, durationScrollMillis)
            }
        }
    }
    

    Initializing from the activity class:

    viewPager.apply {
        scrollDuration = 2000
        adapter = pagerAdapter
    }
    
    0 讨论(0)
提交回复
热议问题