ViewPager(支持库)中的平滑滚动不起作用。

10

我正在编写一个应用程序,使用 ViewPager 托管 Fragment

当我通过编程方式更改 Fragment 时,平滑滚动功能不起作用。我使用了 ViewPager.setCurrentItem(int item, boolean smoothScroll) 方法。

也许有人知道绕过这个 bug 的方法?也许可以使用动画吗?

编辑:我正在使用支持包。问题在于无论我是使用 ViewPager.setCurrentItem(2, true) 还是 ViewPager.setCurrentItem(2, false),结果都相同。视图切换得非常快(不平滑)。


首先,viewpager仅存在于支持包中。现在问题是,您面临的问题是什么?如果您执行setCurrentItem(2, false),它会做什么?能否编辑您的问题以更具体一些? - Jorge Aguilar
1
所以我将mPager.setCurrentItem(1, true);放在一个postrunnable中,以向用户提示该对象是一个viewpager。问题是,当我将其放入postrunnable时,没有动画效果,这就失去了意义。我还有其他方法可以做到这一点吗? - MinceMan
2个回答

17

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

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

这个解决方案很恶劣,但应该能够实际起作用!谢谢,我会尝试实现你的建议。 - Tautvydas
7
如果您使用这个解决方法和 ProGuard,您需要将以下内容添加到您的 ProGuard 配置中:-keepclassmembers class android.support.v4.view.ViewPager { private android.widget.Scroller mScroller; } - Iftah
我看到减速插值器有作用,但是startScroll中的1秒延迟在我的端上似乎没有任何作用。 - SamIAmHarris

-1

对我有效的做法是在mPagerAdapter.notifyDataSetChanged()之后直接调用mPager.setCurrentItem,而不是通过发布一个可运行对象来调用。

以下是一个MonoDroid的示例:

    public void UpdateDetialsView(string type)
    {
        string typeName4 = Java.Lang.Class.FromType(typeof(ParcelRecordComplaintDetailsView)).Name;

        if (_fragments.Count > 3)
        {
            _fragments.RemoveAt(_fragments.Count - 1);

            ////////////////////////////////////////////////////////////
            // Called here it wasn't working for me (Posted or not)

            //_viewPager.Post(new Action(() => { _viewPager.SetCurrentItem(3, true); }));
        }

        _fragments.Add(Fragment.Instantiate(Activity, typeName4));

        _pagerAdapter.NotifyDataSetChanged();

        ////////////////////////////////////////////////////////////
        // Called here it works as expected

        _viewPager.SetCurrentItem(3, true);
    }

在哪里

    protected MyAdapter _pagerAdapter;
    protected ViewPager _viewPager;
    private List<Android.App.Fragment> _fragments;

并且

    public class MyAdapter : Android.Support.V13.App.FragmentStatePagerAdapter
    {
        private List<Fragment> _fragments;

        public override Java.Lang.Object InstantiateItem(View p0, int p1)
        {
            return base.InstantiateItem(p0, p1);
        }

        public MyAdapter(Android.App.FragmentManager fm) : base(fm)
        {

        }

        public MyAdapter(Android.App.FragmentManager fm, List<Android.App.Fragment> fragments) : base(fm)
        {
            _fragments = fragments;
        }

        public override int Count
        {
            //get { return FRAG_PAGES; }
            get { return _fragments.Count; }
        }

        public override Android.App.Fragment GetItem(int p0)
        {
            return _fragments[p0];
        }

        public override float GetPageWidth(int p0)
        {
            //return base.GetPageWidth(p0);

            return (float) (0.5f);
        }

        public override int GetItemPosition(Java.Lang.Object p0)
        {
            //return base.GetItemPosition(p0);
            return PagerAdapter.PositionNone;
        }
    }

有趣。你正在更改片段,是这样吗?我并没有改变片段本身,只是尝试在它们之间切换。我会尝试使用NotifyDataSetChanged()方法的想法。谢谢! - Tautvydas
是的,我正在动态更改它们。我有4个半屏幕面板,它们作为片段实现并托管在ViewPager内。每个面板显示其左侧面板中项目的详细信息(这就是我为什么要动态更新它们的原因)。我认为如果您在实际更改任何内容之前调用NotifyDataSetChanged,它不应该会有任何影响,但我不确定它是否有帮助(如果没有,也许您可以在片段中微小地更改一些内容,然后将其改回来,然后调用NotifyDataSetChanged,以强制执行?)。 - samus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接