3

I have implemented Viewpager2 with left and right preview as shown in Image below. But scrolling only work on Middle Item(2). Not on left(1) and right(3) item preview. How to make scrolling work on left and right preview.

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 code

    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));

            }
            
        }
    });
Rohaitas Tanoli
  • 624
  • 4
  • 16

2 Answers2

4

I honestly didn't find a true mean to make Viewpager2 works with swiping events on left and right preview since Viewpager2 class is final. But things worked out very well with using NestedScrollview.

UPDATED NEW SOLUTION Thanks to CmTiger Who provided a more optimized way for scrolling. I have tested it. You can play with the value LEFT_RIGHT = 300 for left to right scrolling. get value from dp to pixel. however, you like it. This new solution need optimization.

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

OLD SOLUTION

          <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>

Just use this code to make it work. Increase int value of speed to increase speed and vice versa.

  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;
            }
        });
Rohaitas Tanoli
  • 624
  • 4
  • 16
1

I took your solution and made it much simpler and the scrolling is handle natively by the 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 should be equal to the padding we gave to the ViewPager. I modified the motionEvent so the touch will be on the ViewPager and not on the padding area.

CmTiger
  • 74
  • 6
  • 1
    Thanks man! I have updated my answer. You answer was only working at one side of preview. but it was easy. thanks. – Rohaitas Tanoli Jul 04 '22 at 12:37
  • But after thorough testing. there is some problem. This solution needs more optimization in my case. I am ok with the old one. Don't have much time. – Rohaitas Tanoli Jul 04 '22 at 12:56