Android viewpager同步滚动

发布于 2024-12-08 07:57:12 字数 364 浏览 2 评论 0原文

我有两个 ViewPager——Pager1 和 Pager2。我向 Pager1 添加了一个 OnPageChangeListener,并在 onPageScrolled 回调中调用 Pager2.scrollTo(x, y) 来移动它。两个 ViewPager 都可以平滑滚动并且同步,但问题是 Pager2 的内容没有改变。我用 LogCat 检查了它——Pager2 的 instantiateItem() 根本没有被调用。

作为解决方法,我将 Pager2.setCurrentItem() 添加到 Pager1 的 onPageSelected() 回调中。虽然这确实会滚动两个视图,但它并不与像素同步。我想知道是否有一种方法可以实现这种效果,而不必重写实际的 ViewPager 类。

I have two ViewPagers -- Pager1 and Pager2. I added an OnPageChangeListener to Pager1 and in the onPageScrolled callback, I call Pager2.scrollTo(x, y) to move it. Both of the ViewPagers do scroll smoothly and are synchronized, but the problem is that the contents of Pager2 do not change. I checked it with LogCat -- instantiateItem() for Pager2 doesn't get called at all.

As a workaround, I added Pager2.setCurrentItem() to the onPageSelected() callback for Pager1. While this does scroll both Views, it's not synchronized to the pixel. I'm wondering if there's a way to achieve this effect without having to override the actual ViewPager class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猛虎独行 2024-12-15 07:57:12

最适合我的解决方案是在 ViewPager 实例之间的 OnTouchListener 中传递 MotionEvent。尝试过假拖动,但它总是滞后且有问题 - 我需要一个平滑的、类似视差的效果。

因此,我的解决方案是实现一个 View.OnTouchListener。必须缩放 MotionEvent 以补偿宽度差异。

public class SyncScrollOnTouchListener implements View.OnTouchListener {

private final View syncedView;

public SyncScrollOnTouchListener(@NonNull View syncedView) {
    this.syncedView = syncedView;
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    MotionEvent syncEvent = MotionEvent.obtain(motionEvent);
    float width1 = view.getWidth();
    float width2 = syncedView.getWidth();

    //sync motion of two view pagers by simulating a touch event
    //offset by its X position, and scaled by width ratio
    syncEvent.setLocation(syncedView.getX() + motionEvent.getX() * width2 / width1,
            motionEvent.getY());
    syncedView.onTouchEvent(syncEvent);
    return false;
}
}

然后将其设置为您的 ViewPager

    sourcePager.setOnTouchListener(new SyncScrollOnTouchListener(targetPager));

请注意,此解决方案仅在两个寻呼机具有相同方向时才有效。如果您需要它适用于不同的方向 - 调整 syncEvent Y 坐标而不是 X 坐标。

我们还需要考虑一个问题 - 可能导致只有一个寻呼机的最小滑动速度和距离更改页面。

通过向寻呼机添加 OnPageChangeListener 可以轻松修复此问题

sourcePager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            //no-op
        }

        @Override
        public void onPageSelected(int position) {
            targetPager.setCurrentItem(position, true);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            //no-op
        }
    }); 

The solution that worked best for me was to pass MotionEvent in OnTouchListener between ViewPager instances. Tried fake dragging but it was always laggy and buggy - I needed a smooth, parallax-like effect.

So, my solution was to implement a View.OnTouchListener. The MotionEvent has to be scaled to compensate for the difference in width.

public class SyncScrollOnTouchListener implements View.OnTouchListener {

private final View syncedView;

public SyncScrollOnTouchListener(@NonNull View syncedView) {
    this.syncedView = syncedView;
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    MotionEvent syncEvent = MotionEvent.obtain(motionEvent);
    float width1 = view.getWidth();
    float width2 = syncedView.getWidth();

    //sync motion of two view pagers by simulating a touch event
    //offset by its X position, and scaled by width ratio
    syncEvent.setLocation(syncedView.getX() + motionEvent.getX() * width2 / width1,
            motionEvent.getY());
    syncedView.onTouchEvent(syncEvent);
    return false;
}
}

Then set it to your ViewPager

    sourcePager.setOnTouchListener(new SyncScrollOnTouchListener(targetPager));

Note that this solution will only work if both pagers have the same orientation. If you need it to work for different orientations - adjust syncEvent Y coordinate instead of X.

There is one more issue that we need to take into account - minimum fling speed and distance that can cause just one pager to change page.

It can be easily fixed by adding an OnPageChangeListener to our pager

sourcePager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            //no-op
        }

        @Override
        public void onPageSelected(int position) {
            targetPager.setCurrentItem(position, true);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            //no-op
        }
    }); 
誰ツ都不明白 2024-12-15 07:57:12

您尝试过beginFakeDrag()吗?

Have you tried beginFakeDrag()?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文