安卓ViewPager2 setPageMargin未解决

28

我想使用View Pager2实现走马灯,左右两边有预览效果,就像这样:

图片描述

最初我使用的是支持此功能的视图页面1,但现在我认为它已被删除。

    viewPagerhost.setPageMargin(20);

有什么想法可以使用View Pager 2来实现这个吗?


在https://issuetracker.google.com/issues/132249311创建了一个问题。 - Raghunandan
请检查我的答案 https://stackoverflow.com/a/67771069/3586084 - alierdogan7
6个回答

41

MarginPageTransformer 无法满足您的需求。

您必须使用自定义的 setPageTransformer


步骤 1

这是我的扩展方法。

您可以在此文章中查看详细信息:Medium 文章

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

}

第二步

根据您的使用情况设置pageMarginPx和offsetPx。

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

步骤 3

在您的xml中设置布局项目的侧边距。

像这样:

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

1
那篇中等难度的文章真是太好了。我只需要将它转换成Java代码,就能轻松地让它工作。这是更好的答案。如果有人忽略了这个答案或链接,请务必阅读一下。它为我节省了数小时的时间。 - Riot Goes Woof
谢谢你用“ViewCompat.getLayoutDirection(this)== ViewCompat.LAYOUT_DIRECTION_RTL”帮我节省了4个小时的时间。感谢你的帮助。 - Javad B
这段代码只是附带文章的复制。无论如何,做得很好。 - MJ Studio
如果您无法通过xml设置marginLeft和marginRight,请在setPageTransformer()中使用以下代码。例如,在合并布局中。page.updateLayoutParams<ViewGroup.MarginLayoutParams> { marginStart = 100 marginEnd = 100 } - Ajith M A
它能工作。感谢解决方案。 - Reddy
非常好的解决方案,但在我的情况下,第一个和最后一个项目有很大的边距,我不确定如何处理,有什么想法吗? - Alan Donizete

21

现在我们需要在Version 1.0.0-alpha05中使用setPageTransformer()

新特性

  • ItemDecorator与RecyclerView的行为一致。
  • MarginPageTransformer提供了创建页面间距(页面内缩白之外)的能力。
  • CompositePageTransformer提供了组合多个页面转换器的能力。

示例代码

myViewPager2.setPageTransformer(new MarginPageTransformer(1500));

如果你想使用View Pager2实现Carousel,请查看我的以前的答案


15
这并不能像原帖所要求的那样创建预览,这怎么算是个答案呢?它只会扩大页面之间的间隙。 - MDT

4
我使用了 MJ Studio 的方法创建自定义的 PageTransformer,并且还可以按如下方式更改页面边距:

MJ Studio's approach

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

这样你只需要调用以下代码:
viewPager.setPageTransformer(OffsetPageTransformer(offsetPx, pageMarginPx))

0

你可以使用这段代码

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

但是如果你想使用DP,你可以使用下面的函数将PX转换为DP

 private  int pxToDp(int px) {
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

0

MarginPageTransformer 可以帮助定义页面之间的间距。

offscreenPageLimit 可以让您定义应该在屏幕外呈现多少页。

代码示例:

viewPager2.offscreenPageLimit = 3
viewPager2.setPageTransformer(MarginPageTransformer({MARGIN AS PX}));

0
如果有人想要实现这样的情况,即第一项只在右侧有空格,而最后一项只在左侧有空格,可以参考其他答案的建议。

enter image description here

enter image description here

enter image description here

将此代码应用于您的ViewPager2。
viewPagerPhotos.apply {
    adapter = photosAdapter

    clipToPadding = false
    clipChildren = false
    offscreenPageLimit = 3

    val pageMargin = 16.dpToPx(this@MaintenanceCenterDetailsActivity)
    val offset = 24.dpToPx(this@MaintenanceCenterDetailsActivity)
    setPageTransformer { page, position ->
        val pageOffset = position * -(2 * offset + pageMargin)
        if (viewPagerPhotos.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
            if (ViewCompat.getLayoutDirection(viewPagerPhotos) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                page.translationX = -pageOffset
            } else {
                page.translationX = pageOffset
            }
        } else {
            page.translationY = pageOffset
        }
    }
}

在你的视图持有者中,你需要做以下操作。
fun bind(photoUrl: String) {
    with(binding.root) {
        if (itemCount > 1) {
            updateLayoutParams<ViewGroup.MarginLayoutParams> {
                when (layoutPosition) {
                    0 -> {
                        marginStart = 0
                        marginEnd = marginValue
                    }
                    itemCount - 1 -> {
                        marginStart = marginValue
                        marginEnd = 0
                    }
                    else -> {
                        marginStart = marginValue
                        marginEnd = marginValue
                    }
                }
            }
        }

        load(photoUrl) {
            crossfade(true)
        }
    }
}

这是一个将dp转换为px的扩展函数。
fun Int.dpToPx(context: Context): Int {
    val resources = context.resources
    val scale = resources.displayMetrics.density
    return (this * scale).toInt()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接