2

I have recyclerview with horizontal scroll and it snaps by default with LinearSnapHelper or PagerSnapHelper to the center of item. I want to snap to the left side of the each item. Is it possible?

user1730694
  • 442
  • 4
  • 14

1 Answers1

10

You can easily extend PagerSnapHelper to align items by left side. There is one trick only needed with last item.

My solution is:

class AlignLeftPagerSnapHelper : PagerSnapHelper() {
    private var horizontalHelper: OrientationHelper? = null

    override fun findSnapView(layoutManager: RecyclerView.LayoutManager?): View? {
        return getStartView(layoutManager as LinearLayoutManager, getHorizontalHelper(layoutManager))
    }

    private fun getStartView(layoutManager: LinearLayoutManager, helper: OrientationHelper): View? {
        val firstVisibleChildPosition = layoutManager.findFirstVisibleItemPosition()
        val lastCompletelyVisibleChildPosition = layoutManager.findLastCompletelyVisibleItemPosition()
        val lastChildPosition = layoutManager.itemCount - 1

        if (firstVisibleChildPosition != RecyclerView.NO_POSITION) {
            var childView = layoutManager.findViewByPosition(firstVisibleChildPosition)
            if (helper.getDecoratedEnd(childView) < helper.getDecoratedMeasurement(childView) / 2) {
                childView = layoutManager.findViewByPosition(firstVisibleChildPosition + 1)
            } else if (lastCompletelyVisibleChildPosition == lastChildPosition) {
                childView = layoutManager.findViewByPosition(lastChildPosition)
            }
            return childView
        }
        return null
    }

    override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray =
        intArrayOf(distanceToStart(targetView, getHorizontalHelper(layoutManager)), 0)

    override fun findTargetSnapPosition(
        layoutManager: RecyclerView.LayoutManager,
        velocityX: Int,
        velocityY: Int
    ): Int {
        val currentView = findSnapView(layoutManager) ?: return RecyclerView.NO_POSITION
        val currentPosition = layoutManager.getPosition(currentView)

        return if (velocityX < 0) {
            (currentPosition - 1).coerceAtLeast(0)
        } else {
            (currentPosition + 1).coerceAtMost(layoutManager.itemCount - 1)
        }
    }

    private fun distanceToStart(targetView: View, helper: OrientationHelper): Int =
        helper.getDecoratedStart(targetView) - helper.startAfterPadding

    private fun getHorizontalHelper(layoutManager: RecyclerView.LayoutManager): OrientationHelper {
        if (horizontalHelper == null) {
            horizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager)
        }
        return horizontalHelper!!
    }
}
kingston
  • 11,053
  • 14
  • 62
  • 116
msms
  • 101
  • 1
  • 3