Android ViewPager - 多个pageChangeListener无法正常工作

时间:2017-02-23 09:17:00

标签: android android-viewpager

当我尝试添加多个pageChangleListeners时,ViewPager出现了一个奇怪的问题。我试过寻找一个类似描述的帖子/问题,但在这里我们找不到任何一个:

短版本:只有1个onPageChangeListener触发第一页,但是对于第二页,多个侦听器正在触发。

长版: 在我的应用程序中,我需要每个ViewPager都有多个OnPageChangeListeners。尽管我在android文档中找不到任何关于此的确认,但函数名称为#34; addOnPageChangeListener"建议我可以将多个侦听器设置为相同的ViewPager(特别是因为它曾经是" 设置 PageChangeListener"并且他们将其更改为" 添加 PageChangeListener&#34)。现在,我有一些代码需要在我的应用程序中的任何ViewPager中选择页面时运行,所以我创建了自己的ViewPager和OnPageChangeListener类:

public class MyViewPager extends ViewPager
{
    private ArrayList<Sequence> mSequenceList;

    public MyViewPager(Context context)
    {
        super(context);
    }

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

    @Override
    public void setAdapter(PagerAdapter adapter)
    {
        super.setAdapter(adapter);

        mSequenceList = ((MyPagerAdapter)adapter).getSequences();

        addOnPageChangeListener(new MyOnPageChangedListener(mSequenceList));
        Log.i("aaaaa", "added listener from MyViewPager");
    }
}

我也做了自己的页面更改监听器:

public class MyOnPageChangedListener implements MyViewPager.OnPageChangeListener
{
    private static final String TAG = "MyOnPageChangedListener";

    private ArrayList<Sequence> sequenceList;

    public MyOnPageChangedListener(ArrayList<Sequence> sequenceList)
    {
        this.sequenceList = sequenceList;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
    {
        //do nothing
    }

    @Override
    public void onPageSelected(int position)
    {
        Log.i("aaaaa", "selecting page " + position + " from my listener");

        //do something
    }

    @Override
    public void onPageScrollStateChanged(int state)
    {
        //do nothing
    }

我在我的活动OnCreate中也有这个:

mPageChangedListener = new ViewPager.OnPageChangeListener()
        {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
            {
                //do nothing
            }

            @Override
            public void onPageSelected(int position)
            {Log.i("aaaaa", "selecting page " + position + " from activity");
                //do something
            }

            @Override
            public void onPageScrollStateChanged(int state)
            {
                //do nothing
            }
        };

        mViewPager.addOnPageChangeListener(mPageChangedListener);
        Log.i("aaaaa", "added listener from activity");

我在我的活动中使用它来触发第一页的onPageSelected

@Override
protected void onResume()
{
    super.onResume();

    mViewPager.post(new Runnable()
    {
        @Override
        public void run()
        {
            mPageChangedListener.onPageSelected(mViewPager.getCurrentItem());
        }
    });
}

但是当我运行应用程序时,我会遇到一些奇怪的行为。这是日志输出:

02-23 03:08:41.192 17147-17147/com.*** I/aaaaa: added listener from MyViewPager
02-23 03:08:41.193 17147-17147/com.*** I/aaaaa: added listener from activity
02-23 03:08:41.273 17147-17147/com.*** I/aaaaa: selecting page 0 from activity
02-23 03:09:03.609 17147-17147/com.*** I/aaaaa: selecting page 1 from my listener
02-23 03:09:03.609 17147-17147/com.*** I/aaaaa: selecting page 1 from activity

你可以看到两个监听器都被添加了,但是对于第一个页面(索引0),只触发了活动的监听器,而对于第二个页面(索引1),两个监听器都被触发。

这对我来说是一个主要问题,因为必须为每个页面触发我自己的onPageChangedListener

任何人都知道为什么会这样,以及如何解决它?

2 个答案:

答案 0 :(得分:0)

由于您仅在mPageChangedListener上显式调用onPageSelected(),因此它不会经历选择页面的完整循环,因此不会为所有分配的侦听器调用onPageSelected()。 如果查看ViewPager源,可以看到如果触发

,则不会调用dispatchOnPageSelected(int position)
mPageChangedListener.onPageSelected(mViewPager.getCurrentItem());
和你一样。

如果选择的项目已被选中,我错过了setCurrentItem(int position)无效的事实...因此对于初始选择,您应该保留所有侦听器的实例并在每个侦听器上调用onPageSelected()。 之后,使用mViewPager.setCurrentItem(int position)将触发两个(或所有)侦听器。

答案 1 :(得分:0)

当然在发布此问题后1分钟我发现了...我正在为可能面临类似问题的任何人发布解决方案:

问题在于我的活动的onResume()方法。我注意到我只触发我在活动中注册的监听器而不是我的自定义监听器。问题是我无法从活动访问MyOnPageChangedListener,所以我在MyOnPageChangedListener中创建了一个全局变量,并添加了一个get方法来访问它。这是我修改过的课程:

public class MyViewPager extends ViewPager

{
    private ArrayList<Sequence> mSequenceList;

    private MyOnPageChangedListener mPageChangeListener;

    //making the compiler happy
    public MyViewPager(Context context)
    {
        super(context);
    }

    //making the compiler happy
    public MyViewPager(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    @Override
    public void setAdapter(PagerAdapter adapter)
    {
        super.setAdapter(adapter);

        mSequenceList = ((MyPagerAdapter)adapter).getSequences();

        mPageChangeListener = new MyOnPageChangedListener(mSequenceList);
        addOnPageChangeListener(mPageChangeListener);
        Log.i("aaaaa", "added listener from MyViewPager");
    }

    public MyOnPageChangedListener getMyPageChangeListener()
    {
        return mPageChangeListener;
    }
}

这是我更新的onResume:

@Override
protected void onResume()
{
    super.onResume();

    invalidateOptionsMenu();

    //this is to invoke "onPageSelected()" for the first page
    //when the viewpager is first created, and when the activity is resumed
    //(for example when coming back from "edit profile")
    mViewPager.post(new Runnable()
    {
        @Override
        public void run()
        {
            mViewPager.getMyPageChangeListener()
                      .onPageSelected(mViewPager.getCurrentItem());
            mPageChangedListener.onPageSelected(mViewPager.getCurrentItem());
        }
    });
}
然而,这对我来说感觉有点像黑客而不是优雅的解决方案...这也意味着我必须手动为每个我想触发自己的听众的活动做这个。

遗憾的是,没有这样的方法“getAllPageChangedListeners”。

有更好的解决方案吗?

相关问题