Android View Pager2 horizontal carousel

23 views Asked by At

I have a basic carousel logic, set in ViewPager2.PageTransformer I can observe previous and next views, also have applied scaling.

But I need to improve this logic, when it's the first item in the carousel I need it to be shifted left by offset, when it's a last on shift it right by the offset. How to do so?

I can't really figure out how to implement this function, theoretically it's possible to get current's item index, but animation won't be smooth, at least what I tried.

What I currently do:

Find offset by which central view should be moved(offset of the scaled view)

val cardWidthPlusPaddings = view.width + padding * 2F
val desiredCardWidthPlusPaddings = cardWidthPlusPaddings + padding
val cardScale: Float = cardWidthPlusPaddings/desiredCardWidthPlusPaddings

val currentCardWidth = cardWidthPlusPaddings * cardScale
val offset = ((cardWidthPlusPaddings - currentCardWidth)/2) - padding

Setting the traslationX:

It will only move left and right items by scaled offset + paddings, not the central one.

And also I'd like to omit calculation of the right and left cards scaling, can add them later.

view.translationX = position * -(2 * padding + offset)

enter image description here

1

There are 1 answers

0
Mark D On

I was manage to solve it

class PageTransformer : ViewPager2.PageTransformer {

    private val margin = [add your margin] - amount by which card be moved
    private val viewsPadding = [add your View/ViewPager to screen end pad]

    private var size: Int = -1

    override fun transformPage(view: View, position: Float) {
        adapter?.itemCount?.let {
            if (size != it) {
                size = it
            }
        }
        val currentItemIndex = viewPager.currentItem

        val cardWith = view.width
        val desiredCardWidthPlusPaddings = cardWith + margin
        val cardScale: Float = cardWith/desiredCardWidthPlusPaddings.toFloat()

        val scaledCardWidth = cardWith * cardScale
        val centralCardOffset: Float = when (currentItemIndex) {
            0 -> ((cardWith - scaledCardWidth)/2) - margin
            size - 1 -> -(((cardWith - scaledCardWidth)/2) - margin)
            else -> 1F
        }

        with(view) {
            translationX = centralCardOffset + position * -(margin + cardsPadding)
            scaleY = (1 - abs(position) * (1 - cardScale))
            scaleX = cardScale + abs(position) * (1 - cardScale)
        }
    }