Viewpager2 预览左右滑动不起作用。

3
我已经实现了带有左右预览的Viewpager2,如下图所示。但是,仅在中间项(2)上滚动。而不在左侧(1)和右侧(3)的项预览中。 如何使左右预览中的滚动工作

enter image description here

  <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:layout_marginTop="@dimen/_5sdp"
            android:paddingStart="@dimen/_50sdp"
            android:paddingEnd="@dimen/_50sdp"
            />

Java代码

    viewpager.setOffscreenPageLimit(3);
    viewpager.setClipToPadding(false);
    viewpager.setClipChildren(false);


    CompositePageTransformer cpt = new CompositePageTransformer();

    cpt.addTransformer(new MarginPageTransformer(10));
    cpt.addTransformer(new ViewPager2.PageTransformer() {
        @Override
        public void transformPage(@NonNull View page, float position) {
            float r = 1 - Math.abs(position);
            page.setScaleY(0.80f + r * 0.20f);
        }
    });

   viewpager.setPageTransformer(cpt);
   viewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            super.onPageScrolled(position, positionOffset, positionOffsetPixels);

            
            if (position == 0) {
                viewpager.setCurrentItem((int) (A1.list.size() / 2));

            }
            
        }
    });

这是优化的答案 https://dev59.com/Ymkw5IYBdhLWcg3wJXQh#73397935 - Nikunj Paradva
2个回答

4

由于Viewpager2类是final类型的,因此我确实找不到一种真正的方法来使Viewpager2在左右预览上使用滑动事件,但是使用NestedScrollview效果非常好。

更新新的解决方案 感谢CmTiger提供了更优化的滚动方式。我已经测试过了。您可以尝试将LEFT_RIGHT值设置为300,以进行从左到右的滚动。您可以按照自己的喜好将值从dp转换为像素。这个新的解决方案需要优化。

    float last_x = 0;

    nestedScrollView.setOnTouchListener(new View.OnTouchListener() {
        
        int LEFT_RIGHT = -300;   // your offsets
        int RIGHT_LEFT = 300;

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            float x = motionEvent.getX();

            if (x > last_x) {
                motionEvent.offsetLocation(LEFT_RIGHT, 0);
            } else {
                motionEvent.offsetLocation(RIGHT_LEFT, 0);
            }

            last_x = x;

            viewpager.dispatchTouchEvent(motionEvent);
            return false;
        }
    });

旧方案

          <androidx.core.widget.NestedScrollView
            android:id="@+id/nestedScroll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginTop="@dimen/_5sdp"
            android:paddingStart="@dimen/_50sdp"
            android:paddingEnd="@dimen/_50sdp"
            />
        </androidx.core.widget.NestedScrollView>

只需使用此代码即可使其正常工作。增加速度的整数值可提高速度,反之亦然。

  nestedScroll = view.findViewById(R.id.nestedScroll);

    nestedScroll2.setOnTouchListener(new View.OnTouchListener() {
        float start = 0;
        float limit_to_start_moving = 5;
        int speed = 7;
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                // Touch Starts X  DOWN_X
                start = motionEvent.getX();
            }

            if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                // get position
                float X2 = motionEvent.getX();

                if ((X2 - limit_to_start_moving) > start) {
                    // LEFT & RIGHT DIRECTION
                    if (start < X2)
                        viewpager.fakeDragBy((motionEvent.getXPrecision() * speed));
                    else
                        viewpager.fakeDragBy((motionEvent.getXPrecision() * -speed));
                    start = X2;  // old position

                } else if ((X2 + limit_to_start_moving) < start) {

                    if (start < X2)
                        viewpager.fakeDragBy((motionEvent.getXPrecision() * speed));
                    else
                        viewpager.fakeDragBy((motionEvent.getXPrecision() * -speed));
                    start = X2;

                }
            }

            if (motionEvent.getAction() == MotionEvent.ACTION_UP) {

                if (viewpager.isFakeDragging()) {
                    viewpager.endFakeDrag();
                }

            }

            if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {

                if (viewpager.isFakeDragging()) {
                    viewpager.endFakeDrag();
                    if (start > motionEvent.getX()) {
                        viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
                    } else {
                        viewpager.setCurrentItem(viewpager.getCurrentItem() - 1);
                    }
                }

            }

            return false;
        }
    });

   viewpager.setOnTouchListener(new View.OnTouchListener() {
            float lastValue;
            float value;
            float delta;

            @Override
            public boolean onTouch(View view, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    lastValue = event.getX();
                    viewpager.beginFakeDrag();
                } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                    value = event.getX();
                    delta = value - lastValue;
                    viewpager.fakeDragBy(delta * 2);
                    lastValue = value;
                } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {
                    viewpager.endFakeDrag();
                }

                return false;
            }
        });

1
我采用了你的解决方案,并将其简化了许多,滚动效果由ViewPager本身处理:
view.findViewById(R.id.nestScrollView).setOnTouchListener(new View.OnTouchListener() {
        final int x_offset = -Tools.dpToPx(30);
        @Override
        public boolean onTouch(View v, MotionEvent motionEvent) {
            motionEvent.offsetLocation(x_offset,0);
            VP_dynamic_area.dispatchTouchEvent(motionEvent);
            return false;
        }
    });

x_offset应该等于我们给ViewPager设置的padding值。 我修改了motionEvent,使得触摸事件在ViewPager上而不是在padding区域。


1
谢谢你!我已经更新了我的答案。你的答案只在预览的一侧起作用,但很容易解决。谢谢。 - Rohaitas Tanoli
但是在仔细测试后,发现存在一些问题。对于我的情况,此解决方案需要更多的优化。我还可以接受旧的解决方案。时间不太充裕。 - Rohaitas Tanoli

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