I'm searching for a way to add a space between my items using a RecyclerView
and the PagerSnapHelper
.
To demonstrate what I mean here is a gif:
As you can see above between the two images there is a little black space. But these space is only available on scroll. If the scrollState is in SCROLL_STATE_IDLE
the image get centered snapped and are "full width".
That is what I want to achieve.
My idea was to add a new "placeholder" viewType
to my RecyclerView.Adapter
and customize the PagerSnapHelper
to "jump over" the placeholder viewType
(to jump over each second View
would be also possible).
But somehow this isn't working. I can't change the PagerSnaperHelper
(or the SnapHelper
with a lot of duplicated code from the PagerSnapHelper
) to work like I want. Even further while implementing it felt somehow wrong. It felt like "this is not the way it should be".
So - any recommendations or ideas how I can solve this? I'm totally open for all suggestions.
Disclamer:
I know I could use the old ViewPager
for this. But for special reasons I ask for an implementation for a RecyclerView
😉. So please don't suggest to use the ViewPager
here, thanks 😃.
You can try this:
Create two viewType
, the first is your image, the second is a black indent. Then at SCROLL_STATE_IDLE
and SCROLL_STATE_SETTLING
call smoothScrollToPosition(position)
to the desired position.
val pagerSnapHelper = PagerSnapHelper()
val spacePagerSnapHelper = SpacePagerSnapHelper(pagerSnapHelper)
pagerSnapHelper.attachToRecyclerView(recyclerView)
spacePagerSnapHelper.attachToRecyclerView(recyclerView)
And this is the 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")
}
}
}
}
}
}