使用OnPageChangeListener同步两个ViewPagers

And*_*yld 13 android android-viewpager

我正试图同步两个ViewPagers,因为在我之前显然有很多人,而且我已经达到了这个目标:

private ViewPager mNavPager;

private ViewPager mMainPager;

private final OnPageChangeListener mNavPagerListener = new OnPageChangeListener() {

    private boolean mNavDragging;
    private int mScrollPosition;

    @Override
    public void onPageSelected(int position) {
        mScrollPosition = position;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if(mNavDragging)
            mMainPager.scrollTo(positionOffsetPixels, 0);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        switch(state) {
        case ViewPager.SCROLL_STATE_DRAGGING:
        case ViewPager.SCROLL_STATE_SETTLING:
            mNavDragging = true;
            break;
        case ViewPager.SCROLL_STATE_IDLE:
            mNavDragging = false;
            break;
        }
    }
};

private OnPageChangeListener mMainPagerListener = new OnPageChangeListener() {

    private boolean mMainDragging;
    private int mScrollPosition;

    @Override
    public void onPageSelected(int position) {
        mScrollPosition = position;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if(mMainDragging)
            mNavPager.scrollTo(positionOffsetPixels, 0);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        switch(state) {
        case ViewPager.SCROLL_STATE_DRAGGING:
        case ViewPager.SCROLL_STATE_SETTLING:
            mMainDragging = true;
            break;
        case ViewPager.SCROLL_STATE_IDLE:
            mMainDragging = false;
            break;
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

如果其中一个手动滚动,另一个使用滚动状态属性从属于它.它工作得很漂亮,直到物品到达最终位置; 此时,从属寻呼机立即轻弹回到之前选择的项目,就好像没有进行滚动一样.

我曾尝试ViewPager#setCurrentItem(mScrolledPosition)使用各种不同的逻辑约束来调用,但这也不起作用,尽管它偶尔会使情况变得更糟.我觉得好像必须有一些东西可以做到,但我不知道是什么.

如何让奴隶寻呼机保持在正确的位置?

car*_*eli 19

我使用OnPageChangeListener以更容易(更干净)的方式解决了这个问题:

mViewPager1.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

      private int mScrollState = ViewPager.SCROLL_STATE_IDLE;

      @Override
      public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
        if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
          return;
        }
        mViewPager2.scrollTo(mViewPager1.getScrollX(), mViewPager2.getScrollY());
      }

      @Override
      public void onPageSelected(final int position) {

      }

      @Override
      public void onPageScrollStateChanged(final int state) {
        mScrollState = state;
        if (state == ViewPager.SCROLL_STATE_IDLE) {
          mViewPager2.setCurrentItem(mViewPager1.getCurrentItem(), false);
        }
      }
});

mViewPager2.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

      private int mScrollState = ViewPager.SCROLL_STATE_IDLE;

      @Override
      public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
        if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
          return;
        }
        mViewPager1.scrollTo(mViewPager2.getScrollX(), mViewPager1.getScrollY());
      }

      @Override
      public void onPageSelected(final int position) {

      }

      @Override
      public void onPageScrollStateChanged(final int state) {
        mScrollState = state;
        if (state == ViewPager.SCROLL_STATE_IDLE) {
          mViewPager1.setCurrentItem(mViewPager2.getCurrentItem(), false);
        }
      }
});
Run Code Online (Sandbox Code Playgroud)


小智 5

我已经解决了问题而没有使用Listener.因此,您可以将侦听器用于其他一些内容,并使代码看起来更清晰.

我知道很久以前就提出了一个问题.我正在寻找解决方案,并自己解决了.

这就是我的Custom ViewPager代码

public class CustomPager extends ViewPager {
CustomPager mCustomPager;
private boolean forSuper;

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

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

@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
    if (!forSuper) {

        mCustomPager.forSuper(true);
        mCustomPager.onInterceptTouchEvent(arg0);
        mCustomPager.forSuper(false);
    }
    return super.onInterceptTouchEvent(arg0);
}

@Override
public boolean onTouchEvent(MotionEvent arg0) {
    if (!forSuper) {
        mCustomPager.forSuper(true);
        mCustomPager.onTouchEvent(arg0);
        mCustomPager.forSuper(false);
    }
    return super.onTouchEvent(arg0);
}

public void setViewPager(CustomPager customPager) {
    mCustomPager = customPager;
}

public void forSuper(boolean forSuper) {
    this.forSuper = forSuper;
}

@Override
public void setCurrentItem(int item, boolean smoothScroll) {
    if (!forSuper) {
        mCustomPager.forSuper(true);
        mCustomPager.setCurrentItem(item, smoothScroll);
        mCustomPager.forSuper(false);
    }
    super.setCurrentItem(item, smoothScroll);
}

@Override
public void setCurrentItem(int item) {
    if (!forSuper) {
        mCustomPager.forSuper(true);
        mCustomPager.setCurrentItem(item);
        mCustomPager.forSuper(false);
    }
    super.setCurrentItem(item);

}

}
Run Code Online (Sandbox Code Playgroud)

你必须在设置适配器之前和使用ID获取引用之后设置这样的寻呼机.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    backPager=(CustomPager) findViewById(R.id.BackPager);
    frontPager = (CustomPager) findViewById(R.id.frontPager);
    frontPager.setViewPager(backPager);
    backPager.setViewPager(frontPager);
    backPager.setAdapter(your Adapter);
    frontPager.setAdapter(your Adapter);
}
Run Code Online (Sandbox Code Playgroud)

必须在分配适配器之前设置ViewPagers.

  • 如果同时触摸两个视图,此解决方案将崩溃​​. (2认同)

And*_*yld 2

除了有时会错过从属视图上的快速轻弹之外,这一切都正确。然而,出于某种原因,在稳定阶段包含假阻力事件会导致真正的问题。

private ViewPager mNavPager;

private ViewPager mMainPager;

private final OnPageChangeListener mNavPagerListener = new OnPageChangeListener() {

    private int mLastScrollPosition;
    private int mLastPagePosition;

    @Override
    public void onPageSelected(int position) {
        mLastPagePosition = position;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if(mMainPager.isFakeDragging()) {
            int absoluteOffsetPixels = positionOffsetPixels;
            if(mLastPagePosition!=position) {
                absoluteOffsetPixels += (position - mLastPagePosition) * mMainPager.getWidth();
                mLastPagePosition = position;
            }
            Log.d(TAG, "fake nav drag by " + (mLastScrollPosition - absoluteOffsetPixels));
            mMainPager.fakeDragBy(mLastScrollPosition - absoluteOffsetPixels);
            mLastScrollPosition = positionOffsetPixels;
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if(!mNavPager.isFakeDragging()) {
            switch(state) {
            case ViewPager.SCROLL_STATE_DRAGGING:
                if(!mMainPager.isFakeDragging())
                    mMainPager.beginFakeDrag();
                break;
            case ViewPager.SCROLL_STATE_SETTLING:
            case ViewPager.SCROLL_STATE_IDLE:
                if(mMainPager.isFakeDragging()) {
                    mMainPager.endFakeDrag();
                    mLastScrollPosition = 0;
                }
                break;
            }
        }
    }
};

private OnPageChangeListener mMainPagerListener = new OnPageChangeListener() {

    private int mLastScrollPosition;
    private int mLastPagePosition;

    @Override
    public void onPageSelected(int position) {
        mLastPagePosition = position;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if(mNavPager.isFakeDragging()) {
            int absoluteOffsetPixels = positionOffsetPixels;
            if(mLastPagePosition!=position) {
                absoluteOffsetPixels += (position - mLastPagePosition) * mMainPager.getWidth();
                mLastPagePosition = position;
            }
            Log.d(TAG, "fake nav drag by " + (mLastScrollPosition - absoluteOffsetPixels));
            mNavPager.fakeDragBy(mLastScrollPosition - absoluteOffsetPixels);
            mLastScrollPosition = positionOffsetPixels;
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if(!mMainPager.isFakeDragging()) {
            switch(state) {
            case ViewPager.SCROLL_STATE_DRAGGING:
                if(!mNavPager.isFakeDragging())
                    mNavPager.beginFakeDrag();
                break;
            case ViewPager.SCROLL_STATE_SETTLING:
            case ViewPager.SCROLL_STATE_IDLE:
                if(mNavPager.isFakeDragging()) {
                    mNavPager.endFakeDrag();
                    mLastScrollPosition = 0;
                }
                break;
            }
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

编辑

我现在相信,如果没有一些相当大量的自定义代码,这是不可能的。原因本质上是两个ViewPagers 都有一个VelocityTracker内部,用于控制滚动。由于MotionEvent传入的 s 可能不会传递给VelocityTracker每个寻呼机的相同相对时间传递到 s,因此跟踪器有时会得出关于如何反应的不同结论。

然而,可以使用修改后的方法PagerTitleStrip来精确跟踪ViewPager,并将条带捕获的触摸事件直接传输到ViewPager

来源PagerTitleStrip在这里。

一般来说,要完成这项工作,需要做的事情如下:将mPrevText,mCurrText和替换mNextText为您想要使用的类型的视图;删除onAttachedToWindow()onDetachedFromWindow()功能;删除对PagerAdapter处理数据集观察者的调用,并添加一个OnTouchListener到修改后的条带,假装拖动主寻呼机。您还需要将修改后的标题栏添加OnPageChangeListenerViewPager内部侦听器在包外部不可见。

这是一个巨大的痛苦吗?是的。但它有效。我很快就会写得更详细。