ViewPager setCurrentItem(pageId, true) does NOT smoothscroll

前端 未结 13 1113
予麋鹿
予麋鹿 2020-12-02 13:01

I am compiling on SDK 4.03, Samsung Infuse Android 2.2, Support Library for Android 4, and using ViewPager in my app, actual swipe works fine, but when I do



        
相关标签:
13条回答
  • 2020-12-02 13:41

    I'm aware this thread it pretty old, but this is one of the top Google results. I've been going back and forth on how to solve this problem for quite a bit now. None of the solutions above helped me at all. However, I did find a solution that works for me.

    What my setup currently looks like is a listview inside a viewpager. When you click on one of the views it creates a new page and scrolls to it. This was very snappy before, but it seems as though this is because I was calling

    mViewPager.setCurrentItem(intIndex, true);
    

    from inside my OnClickEvent. The viewpager doesn't like this for some reason, so instead, I made this function. It creates a new thread that runs a runnable on the UI thread. This runnable is what tells the ViewPager to scroll to a certain item.

    public static void scrollToIndex(int index) {
    
        final int intIndex = index;
    
        //We're going to make another thread to separate ourselves from whatever
        //thread we are in 
        Thread sepThread = new Thread(new Runnable(){
    
            public void run()
            {
                //Then, inside that thread, run a runnable on the ui thread.
                //MyActivity.getContext() is a static function that returns the 
                //context of the activity. It's useful in a pinch.
                ((Activity)MyActivity.getContext()).runOnUiThread(new Runnable(){
    
                    @Override
                    public void run() {
    
                        if (mSlidingTabLayout != null)
                        {
                            //I'm using a tabstrip with this as well, make sure
                            //the tabstrip is updated, or else it won't scroll
                            //correctly
                            if(mSlidingTabLayout.getTabStripChildCount() <= intIndex)
                            mSlidingTabLayout.updateTabStrip();
    
                            //Inside this thread is where you call setCurrentItem
                            mViewPager.setCurrentItem(intIndex, true);
    
                        }
    
                    }
    
                });
    
             }
        });
    
    
        sepThread.start();
    
    
    }
    

    I hope I have at least helped someone with this problem. Good luck!

    Edit: Looking over my answer, I'm pretty sure you can just run on the ui thread, and it should work. Take that with a grain of salt though, I haven't tested it yet.

    0 讨论(0)
  • 2020-12-02 13:43

    I had the same problem, but today I've found a simple solution. Maybe it will help you. First, lets suppose we have a ViewPager that filled the whole screen. To switch between pages I've created my own custom View with tabs and put it over the ViewPager. Clicking a tab should scroll smoothly to the appropriate page in ViewPager with setCurrentItem(item, true) - but it scrolls instantly, with no smooth! Then I tried to add a simple button (not custom) over the ViewPager + callback:

    @Override
    public void onClick(View v) {
       viewPager.setCurrentItem(item, true);
    }
    

    After that the smooth scroll stared working. So, the solution was very simple: inside the Button class the internal boolean onTouch(...) listener returns true, so it always CONSUMES touch events! Then the smooth scroll started working for my custom tabs view when I substitued "return false" with "return true" in the internal boolean onTouch(...) listener.

    I hope my success story can help you.

    0 讨论(0)
  • 2020-12-02 13:44

    As others later discovered, it is a bug and we have to post it delayed, but it can be quite simple:

    pager.post {
        pager.setCurrentItem(1, true)
    }
    

    Sadly you have to try first bunch of wrong answers to get to this...

    0 讨论(0)
  • 2020-12-02 13:45

    Below code will pause the page for a moment(500 ms) then slide to next.

    import androidx.viewpager.widget.ViewPager;
    
    
    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                viewPager.setCurrentItem(index, true);
            }
        }, 500);
    
    0 讨论(0)
  • 2020-12-02 13:49

    I´ve created this class because I wasn't fully satisfied with the above solutions

    The class overrides setCurrentItem(int item, boolean smoothScroll) and uses reflection to keep this method as original as possible. The key is that velocity is not 0. You only have to replace your current ViewPager with this MyViewPager class and use it like normally:

    import android.content.Context;
    import android.util.AttributeSet;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    import androidx.viewpager.widget.ViewPager;
    
    public class MyViewPager extends ViewPager {
    
        public MyViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        /**
         * Set the currently selected page. If the ViewPager has already been through its first
         * layout with its current adapter there will be a smooth animated transition between
         * the current item and the specified item.
         *
         * @param item         Item index to select
         * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
         */
        @Override
        public void setCurrentItem(int item, boolean smoothScroll) {
            final Class<?> viewpager = ViewPager.class;
            int velocity = 1;
    
            try {
                Field mPopulatePending = viewpager.getDeclaredField("mPopulatePending");
                mPopulatePending.setAccessible(true);
                mPopulatePending.set(this, false);
    
                Method setCurrentItemInternal = viewpager.getDeclaredMethod("setCurrentItemInternal", int.class, boolean.class, boolean.class, int.class);
                setCurrentItemInternal.setAccessible(true);
                setCurrentItemInternal.invoke(this, item, smoothScroll, false, velocity);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 13:52

    This is what i did. I overrode the package-private method smoothScrollTo in ViewPager by putting my own custom subclass in the same package. It was being passed a value of zero, which causes the snapping behavior instead of the smooth scroll.

    package android.support.v4.view;
    
    import android.content.Context;
    import android.util.AttributeSet;
    
    public class MyViewPager extends ViewPager {
    
        public MyViewPager(Context context) {
            super(context);
        }
    
        public MyViewPager(Context context, AttributeSet attr) {
            super(context, attr);
        }
    
        void smoothScrollTo(int x, int y, int velocity) {
            super.smoothScrollTo(x, y, 1);
        }
    }
    

    It worked great, if you want you can calculate and provide actual velocity ISO of just 1.

    0 讨论(0)
提交回复
热议问题