简体   繁体   中英

Android ViewPager2 setPageMargin unresolved

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

在此处输入图片说明

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

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

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

ViewPager2 doesn't have the method setPageMargin as of now (version 1.0.0). However you can create the carousel you want with a RecyclerView.ItemDecoration and a PageTransformer .

The result

在此处输入图片说明

The code

In your Activity/Fragment, setup the ViewPager2:

// MyRecyclerViewAdapter is an standard RecyclerView.Adapter :)
viewPager2.adapter = MyRecyclerViewAdapter() 

// You need to retain one page on each side so that the next and previous items are visible
viewPager2.offscreenPageLimit = 1

// Add a PageTransformer that translates the next and previous items horizontally
// towards the center of the screen, which makes them visible
val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
val currentItemHorizontalMarginPx = resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
val pageTransformer = ViewPager2.PageTransformer { page: View, position: Float ->
    page.translationX = -pageTranslationX * position
    // Next line scales the item's height. You can remove it if you don't want this effect
    page.scaleY = 1 - (0.25f * abs(position))
    // If you want a fading effect uncomment the next line:
    // page.alpha = 0.25f + (1 - abs(position))
}
viewPager2.setPageTransformer(pageTransformer)

// The ItemDecoration gives the current (centered) item horizontal margin so that
// it doesn't occupy the whole screen width. Without it the items overlap
val itemDecoration = HorizontalMarginItemDecoration(
    context,
    R.dimen.viewpager_current_item_horizontal_margin
)
viewPager2.addItemDecoration(itemDecoration)

Add the HorizontalMarginItemDecoration , which is a trivial ItemDecoration :

/**
 * Adds margin to the left and right sides of the RecyclerView item.
 * Adapted from https://stackoverflow.com/a/27664023/4034572
 * @param horizontalMarginInDp the margin resource, in dp.
 */
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
    RecyclerView.ItemDecoration() {

    private val horizontalMarginInPx: Int =
        context.resources.getDimension(horizontalMarginInDp).toInt()

    override fun getItemOffsets(
        outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
    ) {
        outRect.right = horizontalMarginInPx
        outRect.left = horizontalMarginInPx
    }

}

Add the dimensions that control how much of the previous/next item is visible, and current item horizontal margin:

<dimen name="viewpager_next_item_visible">26dp</dimen>
<dimen name="viewpager_current_item_horizontal_margin">42dp</dimen>

在此处输入图片说明

ItemDecoration vs adding margins to the item's layout

If you look at other answers, you'll see that you can achieve the same result without the ItemDecoration , simply by adding left and right margins directly to your item's layout:

<androidx.cardview.widget.CardView
    android:layout_marginLeft="@dimen/pageMarginAndOffset"
    android:layout_marginRight="@dimen/pageMarginAndOffset">

While the result is the same, using an ItemDecoration allows you to re-use the same layout in other places without having to deal with this margins that are needed only when using this layout on a ViewPager.

PageTransformer examples

Google has added a guide on ViewPager2 that has 2 PageTransformer implementations that you can use as an inspiration: https://developer.android.com/training/animation/screen-slide-2

ViewPager2 useful links

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM