Search code examples
androidandroid-fragmentskotlinandroid-viewpagerbottomnavigationview

How to set items in BottomNavigationView selected when swiping fragments in Kotlin


For an android app I have a BottomNavigationView with three items and corresponding fragments. With a ViewPager I can swipe between these three fragments. (The default selection is my navigationItem2.)
My problem is that the items in my bottom navigation only get selected on click, but don't change the selection on swipe while the fragment changes as supposed on swipe.

So how can I achieve that the items get selected on swipe?

My MainActivity.kt

class MainActivity : AppCompatActivity() {

private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener {item->
    when(item.itemId){
        R.id.navigationItem1 ->{
            replaceFragment(Fragment1())
            viewPager.currentItem = 0
            return@OnNavigationItemSelectedListener true
        }
        R.id.navigationItem2 ->{
            replaceFragment(Fragment2())
            viewPager.currentItem = 1
            return@OnNavigationItemSelectedListener true
        }
        R.id.navigationItem3 ->{
            replaceFragment(Fragment3())
            viewPager.currentItem = 2
            return@OnNavigationItemSelectedListener true
        } else -> viewPager.currentItem = 1
    }
    false
}

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

    val pageAdapter = FragmentPagerAdapter(supportFragmentManager)
    viewPager.adapter = pageAdapter

    bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
    bottomNavigation.selectedItemId = R.id.navigationItem2

My activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:fitsSystemWindows="true"
    android:background="?attr/backgroundcolor"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/fragmentContainer"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintBottom_toTopOf="@+id/bottomNavigation">
        </FrameLayout>    

    </androidx.viewpager.widget.ViewPager>

    <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottomNavigation"
            app:menu="@menu/bottom_nav_menu"
            android:background="@android:color/white"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintVertical_bias="1.0"
            app:layout_constraintHorizontal_bias="1.0"/>

</androidx.constraintlayout.widget.ConstraintLayout>

My FragmentPageAdapter.kt

class FragmentPagerAdapter (fragmentManager: FragmentManager): FragmentPagerAdapter(fragmentManager){

override fun getItem(position: Int): Fragment {
    return when (position){
        0 -> Fragment1.newInstance()
        1 -> Fragment2.newInstance()
        2 -> Fragment3.newInstance()
        else -> Fragment2.newInstance()
    }
}

override fun getCount() = 3
}

Solution

  • You can use addOnPageChangeListener of the ViewPager and on the onPageSelected function you can set the current item.

    viewPager!!.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
    
                override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                    //alerta("menu",position.toString())
                }
    
                override fun onPageSelected(position: Int) {
                        bottomNavigationView!!.getMenu().getItem(position).setChecked(true)
    
                }
    
                override fun onPageScrollStateChanged(state: Int) {
    
                }
            })