Search code examples
androidandroid-layoutkotlincarousel

Custom layout manager scroll/animation


What I'm trying to do.

Create a simple carousel with RecyclerView.

Problem

  1. Initially the view is not snap to center and the view is not getting the style I intended to.(i.e, the item which is fully visible should be bigger than other, when scroll by finger it works fine)
  2. When scroll programmatically the view is not getting snap effect like it does when scroll with finger.

See the attached gif below for example.

enter image description here

Question

  1. How to have the style as intended (i.e the fully visible item is bigger) when started.
  2. How to get the style when scroll to button is click. (It scrolls to correct position the only problem is not getting the style as intended and its not snap to center)

Full code here on github

Here's the code for custom LayoutManager

open class CarouselLayoutManager(
    context: Context,
    orientation: Int,
    reverseLayout: Boolean
) : LinearLayoutManager(context, orientation, reverseLayout) {

private val mShrinkAmount = 0.15f
private val mShrinkDistance = 0.9f

override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
    scrollVerticallyBy(0, recycler, state)
    super.onLayoutChildren(recycler, state)
}

override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
    val orientation = orientation
    if (orientation == LinearLayoutManager.HORIZONTAL) {
        val scrolled = super.scrollHorizontallyBy(dx, recycler, state)

        val midpoint = width / 2f
        val d0 = 0f
        val d1 = mShrinkDistance * midpoint
        val s0 = 1f
        val s1 = 1f - mShrinkAmount
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val childMidpoint = (getDecoratedRight(child) + getDecoratedLeft(child)) / 2f
            val d = Math.min(d1, Math.abs(midpoint - childMidpoint))
            val scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0)
            child.scaleX = scale
            child.scaleY = scale
        }
        return scrolled
    } else {
        return 0
    }
}

override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
    val orientation = orientation
    if (orientation == LinearLayoutManager.VERTICAL) {
        val scrolled = super.scrollVerticallyBy(dy, recycler, state)
        val midpoint = height / 2f
        val d0 = 0f
        val d1 = mShrinkDistance * midpoint
        val s0 = 1f
        val s1 = 1f - mShrinkAmount
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val childMidpoint = (getDecoratedBottom(child) + getDecoratedTop(child)) / 2f
            val d = Math.min(d1, Math.abs(midpoint - childMidpoint))
            val scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0)
            child.scaleX = scale
            child.scaleY = scale
        }
        return scrolled
    } else {
        return 0
    }
}

}


Solution

  • Finally I have solved the problem by using this libraries/examples

    1. DiscreteScrollView
    2. android-viewpager-transformers

    Here is the final result.

    For full code see Carousel Demo

    enter image description here