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