ViewPager setCurrentItem(pageId,true)不会smoothscroll

时间:2012-08-14 23:25:02

标签: android android-layout

我正在编译SDK 4.03,三星Infuse Android 2.2,Android 4支持库,并在我的应用程序中使用ViewPager,实际滑动工作正常,但当我做

viewPager.setCurrentItem(id); // , or
viewPager.setCurrentItem(id, true);  

它不会平滑滚动,但会立即切换视图。虽然文档明确指出这是将第二个参数设置为true的目的。怎么了?

13 个答案:

答案 0 :(得分:42)

我通过创建一个使用反射覆盖ViewPager.mScroller的MyViewPager来解决这个问题。

public class MyViewPager extends ViewPager {

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setMyScroller();
    }

    private void setMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new DecelerateInterpolator());
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 1000 /*1 secs*/);
        }
    }
}

答案 1 :(得分:16)

这就是我所做的。我通过将自己的自定义子类放在同一个包中来覆盖smoothScrollTo中的包私有方法ViewPager。它传递的值为零,这会导致捕捉行为而不是平滑滚动。

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

它很有效,如果你想要你可以计算并提供仅为1的实际速度ISO。

答案 2 :(得分:9)

我在处理程序中调用了setCurrentItem函数,它对我来说很好。

new Handler().post(new Runnable() {
        @Override
        public void run() {
            myViewPager.setCurrentItem(1, true);
        }
    });

希望这有帮助。

答案 3 :(得分:6)

我知道这个帖子很老了,但这是Google最重要的结果之一。我一直在回顾如何解决这个问题。上面的解决方案都没有帮助我。但是,我确实找到了适合我的解决方案。

我目前的设置是viewpager中的listview。当您单击其中一个视图时,它会创建一个新页面并滚动到该页面。这之前非常活泼,但似乎这是因为我打电话

mViewPager.setCurrentItem(intIndex, true);

来自我的OnClickEvent。由于某种原因,viewpager不喜欢这个,所以相反,我做了这个功能。它创建了一个在UI线程上运行runnable的新线程。这个runnable告诉ViewPager滚动到某个项目。

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


}

我希望我至少能帮助解决这个问题的人。祝你好运!

编辑:看看我的回答,我很确定你可以在ui线程上运行,它应该可以工作。拿着那粒盐,但我还没有测试过。

答案 4 :(得分:1)

ViewPager已经从版本5改为很多。其中一些可能与您的问题有关的更改:

  • 修复了ViewPager(修订版5和6)中用户界面行为的错误
  • 修复了ViewPager(修订版9)
  • 的大量错误

假设你的代码应该运行得很好,我最好的猜测是你的支持库不是最新的。如果不是,请尝试更新库。

答案 5 :(得分:1)

我之所以创建这个类是因为我对上述解决方案不完全满意

该类重写import pandas as pd # Empty list to store dataframe rows df_rows = [] # Read all text files for tf in text_files: # For each file with open(tf) as f: # Empty dictionary to store column names and values df_dict = {} # For each line for line in f: # Split by tab k, v = line.split('\t') # Column name as key, value as value df_dict[k] = v # Add the dictionary to list df_rows.append(df_dict) # Read the list of dictionaries as a dataframe df = pd.DataFrame(df_rows) # Preview dataframe df.head() 并使用反射使该方法尽可能保持原始。关键是速度不为0。 您只需用此setCurrentItem(int item, boolean smoothScroll)类替换当前的ViewPager并像往常一样使用它即可:

MyViewPager

答案 6 :(得分:0)

我遇到了同样的问题,但今天我找到了一个简单的解决方案。也许它会帮助你。 首先,假设我们有一个填充整个屏幕的ViewPager。要在页面之间切换,我已经使用制表符创建了我自己的自定义视图并将其放在ViewPager上。单击选项卡应使用setCurrentItem(item,true)顺利滚动到ViewPager中的相应页面 - 但它会立即滚动,没有平滑!然后我尝试在ViewPager +回调上添加一个简单的按钮(不是自定义):

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

之后,顺畅的滚动盯着工作。因此,解决方案非常简单:在Button类内部,内部布尔值onTouch(...)侦听器返回true,因此它总是消耗触摸事件!然后,当我在内部布尔值onTouch(...)侦听器中用“return true”替换“return false”时,平滑滚动开始为我的自定义选项卡视图工作。

我希望我的成功故事可以帮助你。

答案 7 :(得分:0)

对于那些使用Xamarin的人(虽然这种方法也适用于Java)我可以根据上面的答案建议使用下一种方法(来自Android支持库v7 AppCompat 19.1.0的ViewPager):

public void ScrollSmooth(int i)
{
    var jClass = JNIEnv.GetObjectClass(_pager.Handle);
    var jMethod = JNIEnv.GetMethodID(jClass, "setCurrentItemInternal", "(IZZI)V");
    JNIEnv.CallVoidMethod (_pager.Handle, jMethod, new JValue (i), new JValue (true), new JValue (false), new JValue (1));
}

它依赖于http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/view/ViewPager.java

中的ViewPager实现

答案 8 :(得分:0)

浪费了一整天后,我发现一个解决方案将offscreenPageLimit设置为总数。页面的

请遵循此https://stackoverflow.com/a/54800154/9097612

答案 9 :(得分:0)

请注意此变量mFirstLayout- 在viewpager回调onAttachedToWindow时(例如在recyclerview上)将其设置为true,因此不会使用smoothScroll。您应该重写onAttachedToWindow以控制mFirstLayout变量。像这样:

        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            try {
                Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
                mFirstLayout.setAccessible(true);
                mFirstLayout.set(this, false);
                getAdapter().notifyDataSetChanged();
                setCurrentItem(getCurrentItem());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

答案 10 :(得分:0)

下面的代码将暂停页面一会儿(500毫秒),然后滑动到下一个页面。

import androidx.viewpager.widget.ViewPager;


new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            viewPager.setCurrentItem(index, true);
        }
    }, 500);

答案 11 :(得分:0)

正如其他人后来发现的那样,这是一个错误,我们不得不延迟发布,但这可能非常简单:

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

可悲的是,您必须尝试第一堆错误答案才能解决此问题……

答案 12 :(得分:-5)

尝试使用此代码:

viewPager.postDelayed(new Runnable()
{
    @Override
    public void run()
    {
        viewPager.setCurrentItem(id, true);
    }
}, 100);