使用PagerSnapHelper

时间:2018-08-08 12:44:35

标签: android android-layout android-recyclerview pagersnaphelper

我正在寻找一种使用RecyclerViewPagerSnapHelper在项目之间添加空格的方法。

为了展示我的意思,这里是一个gif:

如您在上面的两个图像之间所看到的,有一个黑色的空白。但是这些空间仅在滚动显示中可用。如果scrollStateSCROLL_STATE_IDLE中,则图像将居中对齐并变为“全宽”。

那是我想要实现的。

我的想法是向我的viewType添加一个新的“占位符” RecyclerView.Adapter ,并自定义PagerSnapHelper以“跳过” 占位符viewType (也可以跳过每秒View)。 但是,这不起作用。我无法将PagerSnaperHelper(或SnapHelper中的PagerSnapHelper中包含很多重复的代码)更改为我想要的样子。在实施过程中,甚至更进一步,感觉还是有些错误。感觉就像“这不是应该的样子”。

那么-有什么建议或想法可以解决这个问题? 我完全愿意接受所有建议。

免责声明:
我知道我可以为此使用旧的ViewPager。但是出于特殊原因,我要求实现RecyclerView。因此,请不要在这里建议使用ViewPager,谢谢。

2 个答案:

答案 0 :(得分:2)

您可以尝试以下操作: 创建两个viewType,第一个是您的图像,第二个是黑色凹痕。然后在SCROLL_STATE_IDLESCROLL_STATE_SETTLING处调用smoothScrollToPosition(position)到所需位置。

val pagerSnapHelper = PagerSnapHelper()
val spacePagerSnapHelper = SpacePagerSnapHelper(pagerSnapHelper)
pagerSnapHelper.attachToRecyclerView(recyclerView)
spacePagerSnapHelper.attachToRecyclerView(recyclerView)

这是SpacePagerSnapHelper

/**
 * This is an [RecyclerView.OnScrollListener] which will scrolls
 * the [RecyclerView] to the next closes position if the
 * position of the snapped View (calculated by the given [snapHelper] in [SnapHelper.findSnapView])
 * is odd. Because each odd position is a space/placeholder where we want to jump over.
 *
 * See also [this SO question](https://stackoverflow.com/q/51747104).
 */
class SpacePagerSnapHelper(
        private val snapHelper: SnapHelper
) : RecyclerView.OnScrollListener() {

    private enum class ScrollDirection {
        UNKNOWN, LEFT, RIGHT
    }

    private var scrollDirection: ScrollDirection = UNKNOWN

    fun attachToRecyclerView(recyclerView: RecyclerView) {
        recyclerView.addOnScrollListener(this)
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        scrollDirection = if (dx > 0) RIGHT else LEFT
    }

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        when (newState) {
            RecyclerView.SCROLL_STATE_IDLE -> onPageChanged(recyclerView)
            RecyclerView.SCROLL_STATE_SETTLING -> onPageChanged(recyclerView)
        }
    }

    private fun onPageChanged(recyclerView: RecyclerView) {
        val layoutManager = recyclerView.layoutManager
        val viewToSnap = snapHelper.findSnapView(layoutManager)
        viewToSnap?.let {
            val position = layoutManager.getPosition(it)
            // Only "jump over" each second item because it is a space/placeholder
            // see also MediaContentAdapter.
            if (position % 2 != 0) {
                when (scrollDirection) {
                    LEFT -> {
                        recyclerView.smoothScrollToPosition(position - 1)
                    }
                    RIGHT -> {
                        recyclerView.smoothScrollToPosition(position + 1)
                    }
                    UNKNOWN -> {
                        Timber.i("Unknown scrollDirection... Don't know where to go")
                    }
                }
            }
        }
    }
}

答案 1 :(得分:0)

UgAr0FF的解决方案通常可以使用,但是也会导致不必要的滚动行为:

how it shouldn't look

如您所见,PagerSnapHelper首先尝试着重于分隔线,然后决定移至下一项。我修复了滚动行为,使其看起来像这样:

how it should look

这是代码:

import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_SETTLING


class PagerSnapAndSkipDividerHelper : PagerSnapHelper() {

    private var dx = 0

    override fun attachToRecyclerView(recyclerView: RecyclerView?) {
        super.attachToRecyclerView(recyclerView)
        recyclerView?.addOnScrollListener(onScrollListener)
    }

    override fun findTargetSnapPosition(
        layoutManager: RecyclerView.LayoutManager?,
        velocityX: Int,
        velocityY: Int
    ): Int = getNextNonDividerPosition(
        super.findTargetSnapPosition(layoutManager, velocityX, velocityY)
    )

    private fun getNextNonDividerPosition(position: Int) =
        if (position % 2 == 0) position else if (dx > 0) position + 1 else position - 1

    private val onScrollListener = object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            this@PagerSnapAndSkipDividerHelper.dx = dx
        }

        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            if (listOf(SCROLL_STATE_IDLE, SCROLL_STATE_SETTLING).contains(newState)) {
                val viewToSnapTo = findSnapView(recyclerView.layoutManager) ?: return
                val position = recyclerView.layoutManager?.getPosition(viewToSnapTo) ?: return
                val nonDividerPosition = getNextNonDividerPosition(position)
                if (position != nonDividerPosition) {
                    recyclerView.smoothScrollToPosition(nonDividerPosition)
                }
            }
        }
    }
}

像这样设置:

PagerSnapAndSkipDividerHelper().attachToRecyclerView(recyclerView)