Search code examples
androidkotlinsliding

Viewpager2 Android : A Next button on the view generates two slides to the right


I'm stuck on viewpager2 problem on Android. I have a viewpager2 creating some fragments depending on the position. Each fragment has a next button to navigate horizontally in the view pager.

But when I asked for the next page from the button, I had the action of sliding twice. It like the method createFragment from the adapter was called twice, due to the preload of the fragment borders...

Activity who manage the view pager:

class ConfigurationActivity : AppCompatActivity() {
    private var viewPager : ViewPager2? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_configuration)

        viewPager = viewPager2
        val instance = this

        viewPager!!.apply {
            isUserInputEnabled = true
            orientation = ViewPager2.ORIENTATION_HORIZONTAL

            if(viewPager!!.adapter == null)
                viewPager!!.adapter = ConfigAdapter(supportFragmentManager, lifecycle, instance, 2)
        }

        viewPager!!.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)          
                currentItem = position
            }
        })
    }

    companion object{
        private var currentItem : Int = 0

        fun nextPage(instance : ConfigurationActivity, currentPosition : Int?){
            instance.viewPager!!.currentItem = currentItem + 1
        }
    }
}

The FragmentStateAdapter

class ConfigAdapter(fm: FragmentManager, lc : Lifecycle, private val instance : ConfigurationActivity, configSnapshot : ArrayList<Configuration>) : FragmentStateAdapter(fm, lc) {
    private val configSize = configSnapshot.size

    override fun getItemCount(): Int {
        val length = configSize + 3
        instance.pageIndicatorView.count = length
        return length
    }

    override fun createFragment(position: Int): Fragment {
        Timber.d("creating fragment at position $position")
        return when(position){
                0 -> WelcomeFragment(instance)
                in 1..configSize /* position between 1 and configSize (included) */ -> ConfigureFragment(instance, position-1)
                1 + configSize -> IdentifyFragment(instance)
                2 + configSize -> EndFragment()
                else -> Fragment()
            }
    }
}

A fragment example:

class ConfigureFragment(private val instance : ConfigurationActivity, private val configPosition: Int) : Fragment() {
...
   view.button_continue.setOnClickListener {
       nextPage(instance, configPosition+1)
   }
...
}

Solution

  • Try like this way:-

    • First of all change viewPager variable private to public in Activity like removing private keyword.

      var viewPager : ViewPager2? = null

    • In fragment change setOnClickListener method like below:

      view.button_continue.setOnClickListener { instance!!.viewPager!!.arrowScroll(View.FOCUS_RIGHT) }

    *Suggestion:

    • In fragment, we can get parent activity instance and use this way instead of passing activity instance to each fragment.

      val instance = ((activity as AppCompatActivity) as ConfigurationActivity)