27

I want to implement Carousel using View Pager2 with preview of left and right page like this:

enter image description here

Initially I was using view pager1 which supported. Now I think it's removed

    viewPagerhost.setPageMargin(20);

Any idea how we can achieve this using View Pager 2

Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154

5 Answers5

40

MarginPageTransformer cannot help your need.

You must use custom setPageTrarnsformer.


Step 1

Here is my Extension Method for this.

you can check detail in this article Medium article

fun ViewPager2.setShowSideItems(pageMarginPx : Int, offsetPx : Int) {

    clipToPadding = false
    clipChildren = false
    offscreenPageLimit = 3

    setPageTransformer { page, position ->

        val offset = position * -(2 * offsetPx + pageMarginPx)
        if (this.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
            if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                page.translationX = -offset
            } else {
                page.translationX = offset
            }
        } else {
            page.translationY = offset
        }
    }

}

Step 2

set pageMarginPx and offsetPx with your use case.

<resources>
    <dimen name="pageMargin">20dp</dimen>
    <dimen name="pagerOffset">30dp</dimen>
    <dimen name="pageMarginAndoffset">50dp</dimen>
</resources>

Step 3

set your side margin of layout item in your xml.

like this

    <androidx.cardview.widget.CardView
            app:cardCornerRadius="12dp"

            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"

            android:layout_marginLeft="@dimen/pageMarginAndoffset"
            android:layout_marginRight="@dimen/pageMarginAndoffset"

            android:layout_width="match_parent"
            android:layout_height="match_parent">
MJ Studio
  • 3,947
  • 1
  • 26
  • 37
  • 1
    That medium article is a godsend. All I had to do was convert it to java and it worked so simply. This is the better answer. To anyone overlooking this answer or the link, definitely give it a read. it saved me hours. – Riot Goes Woof Mar 05 '20 at 17:07
  • U save me with "ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL". its take 4 hours. thank man – Javad Jun 28 '20 at 18:06
  • This code is just a copy of the attached article. Anyway good job. – MJ Studio Jun 30 '20 at 01:16
  • Use the below code inside setPageTransformer (), if you are not able to set marginLeft, marginRight via xml. Ex: In a merge layout. page.updateLayoutParams { marginStart = 100 marginEnd = 100 } – Ajith M A Nov 19 '20 at 16:24
  • really nice solution, but in my case, the first and last item has a huge margin, and I am not sure on how to handle it, any idea? – Alan Donizete Mar 23 '22 at 20:47
21

Now we need to use setPageTransformer() in Version 1.0.0-alpha05

New features

  • ItemDecorator introduced with a behaviour consistent with RecyclerView.
  • MarginPageTransformer introduced to provide an ability to create space between pages (outside of page inset).
  • CompositePageTransformer introduced to provide an ability to combine multiple PageTransformers.

SAMPLE CODE

myViewPager2.setPageTransformer(new MarginPageTransformer(1500));

Check out my previous answer if you want to implement Carousel using View Pager2

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • 14
    this doesn't create preview like OP asks, how is this even an answer ? it just widens the gap between pages. – MDT May 16 '21 at 07:33
4

I used MJ Studio's approach to create my custom PageTransformer that also changes the page margin as follows:

class OffsetPageTransformer(
    @Px private val offsetPx: Int,
    @Px private val pageMarginPx: Int
) : ViewPager2.PageTransformer {

    override fun transformPage(page: View, position: Float) {
        val viewPager = requireViewPager(page)
        val offset = position * -(2 * offsetPx + pageMarginPx)
        val totalMargin = offsetPx + pageMarginPx

        if (viewPager.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
            page.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                marginStart = totalMargin
                marginEnd = totalMargin
            }

            page.translationX = if (ViewCompat.getLayoutDirection(viewPager) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                -offset
            } else {
                offset
            }
        } else {
            page.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                topMargin = totalMargin
                bottomMargin = totalMargin
            }

            page.translationY = offset
        }
    }

    private fun requireViewPager(page: View): ViewPager2 {
        val parent = page.parent
        val parentParent = parent.parent
        if (parent is RecyclerView && parentParent is ViewPager2) {
            return parentParent
        }
        throw IllegalStateException(
            "Expected the page view to be managed by a ViewPager2 instance."
        )
    }
}

That way you can just call:

viewPager.setPageTransformer(OffsetPageTransformer(offsetPx, pageMarginPx))
Gnzlt
  • 4,383
  • 2
  • 22
  • 24
0

you can use this code

   viewPager.setPageTransformer(new MarginPageTransformer(margin as PX));

but if you want to use DP you can use the below function for convert PX to DP

 private  int pxToDp(int px) {
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
A.Hosein
  • 182
  • 1
  • 10
0

MarginPageTransformer helps to define spaces between pages.

offscreenPageLimit let you define how many pages should be rendered offscreen.

Sample of the code:

viewPager2.offscreenPageLimit = 3
viewPager2.setPageTransformer(MarginPageTransformer({MARGIN AS PX}));
dilix
  • 3,761
  • 3
  • 31
  • 55