Search code examples
androidkotlinandroid-viewpagerandroid-viewpager2

ViewPager2 - Slider transition sliding too fast


I have implemented from the documentation of viewpager2 the follow animation

private const val MIN_SCALE = 0.85f
private const val MIN_ALPHA = 0.5f

class ZoomOutPageTransformer : ViewPager2.PageTransformer {

    override fun transformPage(view: View, position: Float) {
        view.apply {
            val pageWidth = width
            val pageHeight = height
            when {
                position < -1 -> { // [-Infinity,-1)
                    // This page is way off-screen to the left.
                    alpha = 0f
                }
                position <= 1 -> { // [-1,1]
                    // Modify the default slide transition to shrink the page as well
                    val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
                    val vertMargin = pageHeight * (1 - scaleFactor) / 2
                    val horzMargin = pageWidth * (1 - scaleFactor) / 2
                    translationX = if (position < 0) {
                        horzMargin - vertMargin / 2
                    } else {
                        horzMargin + vertMargin / 2
                    }

                    // Scale the page down (between MIN_SCALE and 1)
                    scaleX = scaleFactor
                    scaleY = scaleFactor

                    // Fade the page relative to its size.
                    alpha = (MIN_ALPHA +
                            (((scaleFactor - MIN_SCALE) / (1 - MIN_SCALE)) * (1 - MIN_ALPHA)))
                }
                else -> { // (1,+Infinity]
                    // This page is way off-screen to the right.
                    alpha = 0f
                }
            }
        }
    }
}

Now, in my activity I wraped this animation with a Handler to automatically swipe, but is going really fast that I cant even notice when its sliding

private fun slideViewPager(){
    var currentPage = 0
    var timer: Timer? = null
    val DELAY_MS: Long = 2000 //delay in milliseconds before task is to be executed
    val PERIOD_MS: Long = 3000
        val handler = Handler()
        val update = Runnable {
            if (currentPage == NUM_PAGES - 1) {
                currentPage = 0
            }
            viewPager.setCurrentItem(currentPage++, true)
        }

        timer = Timer() // This will create a new Thread
        timer!!.schedule(object : TimerTask() { // task to be scheduled
            override fun run() {
                handler.post(update)
            }
        }, DELAY_MS, PERIOD_MS)
    }

I have adjusted the delay from the handler, but is not that the problem, because that just delays when its gonna change to the other page, but the transition during this change is really fast, how can I slow it down ?


Solution

  • I have encountered a similar problem when working with ViewPager2. I had two items in my ViewPager, and put the switch to the next item as the action of a button. The first time you press it, the animation is instantaneous, like you describe. However, in my setup, if you press again on it, it scrolls back to the left. Once it does that, the animation works correctly (both left and right).

    From what I can tell from your code, in your case you continue to scroll in a single direction - hence you only observe the instantaneous scrolling. Try to play around with it and make it scroll back, instead of only forward. See if the animation appears correctly in that case.

    EDIT: If you find that the same behavior applies in your case as well, you can apply a completely inelegant hack:

    You can "browse" through your ViewPager's items when you're opening up your activity, as quickly as possible. Then, after going through each item, switch back to the first item and then just apply whatever logic you have now. If you do this, the items will already be "loaded" and the animations will work.

    Of course, while you're doing that in the "background", you can display a progress loader when you first get into the activity, and once you've scrolled back to the first item, display your activity. The user will think the activity is "loading", but in reality you will be going through each of your ViewPager's items, effectively "pre-loading" them.

    Completely ugly solution, but it should work. I hope someone can come up with a better one than this, as I don't exactly know the reason why the animation isn't playing correctly the first time.