androidandroid-viewpager2

Viewpager2 scrolling on preview left and right is not working


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

            }
            
        }
    });

Solution

  • 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 IN KOTLIN Thanks to CmTiger I have created a better solution

    1: Add this to Nested ScrollView

       var last_x = 0f
     
       viewpager2Scroller.setOnTouchListener(object : OnTouchListener {
                var LEFT_RIGHT =  (padding * -1) // your offsets
                var RIGHT_LEFT = padding
                override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
                    val x = motionEvent.xPrecision
                    if (x > last_x) {
                        motionEvent.offsetLocation(LEFT_RIGHT.toFloat(), 0f)
                    } else {
                        motionEvent.offsetLocation(RIGHT_LEFT.toFloat(), 0f)
                    }
                    last_x = x
                    viewpager2.dispatchTouchEvent(motionEvent)
                    return false
                }
            })
    

    2: Add this To Viewpager2

      viewpager2.setOnTouchListener(object : View.OnTouchListener {
                var lastValue = 0f
                var value = 0f
                var delta = 0f
                override fun onTouch(view: View, event: MotionEvent): Boolean {
                    if (event.action == MotionEvent.ACTION_DOWN) {
                        lastValue = event.x
                        viewpager2.beginFakeDrag()
                    } else if (event.action == MotionEvent.ACTION_MOVE) {
                        value = event.x
                        delta = value - lastValue
                        viewpager2.fakeDragBy(delta * 2)
                        lastValue = value
                    } else if (event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP) {
                        viewpager2.endFakeDrag()
                    }
                    return false
                }
            })
    

    To Handle Crash when setting the item ourself

    if (!binding.viewpager2.isFakeDragging) {
            binding.viewpager2.setCurrentItem(list.size / 2, 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;
                }
            });