BottomNavigation View with some magic

On my previous project I used this library as implementing of BottomNavigationView. I was really enjoying the way author implemented work with onNavigationItemSelectedListener and after that, on my next projects, I wanted to implement it for default BottomNavigationView. And in this article I will show you how to write and use it in MVVM architecture.

Implementing

  1. Create interface
<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.activity.home.MainActivity">

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

   <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFF"
        android:elevation="8dp"
        app:itemIconTint="@color/selector_bot_nav_color"
        app:itemTextColor="@color/selector_bot_nav_color"
        app:labelVisibilityMode="labeled"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/navigation_menu" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

2. Create 3 empty fragments with label in the centre of the screen

class HomeFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_home, container, false)
    }
} 

3.Create Enum with bottom navigation tabs

enum class BottomNavigationPage {

    TAB_HOME,

    TAB_EVENTS,

    TAB_LIBRARY

}

4. Create ViewModel for MainActivity

classMainViewModel : ViewModel() {

        ////////////////////////////////////////////////////////////////////
        /////////////// Live Data with getters ////////////////
        ///////////////////////////////////////////////////////////////////

        private val _homeItemClickedLD = MutableLiveData<Unit>()
        val homeItemClickedLD: LiveData<Unit> get() = _homeItemClickedLD

        private val _eventsItemClickedLD = MutableLiveData<Unit>()
        val eventsItemClickedLD: LiveData<Unit> get() = _eventsItemClickedLD
        
        private val _libraryItemClickedLD = MutableLiveData<Unit>()
        val libraryItemClickedLD: LiveData<Unit> get() = _libraryItemClickedLD 

        //////////////////////////////////////////////////////////////////// 
        //////////////////////////////// Calls /////////////////////////
        ///////////////////////////////////////////////////////////////////

        fun onBottomItemChanged(position: Int) {
                when(values()[position]) {
                    TAB_HOME -> _homeItemClickedLD.execute()
                    TAB_EVENTS -> _eventsItemClickedLD.execute()
                    TAB_LIBRARY -> _libraryItemClickedLD.execute()
                }
        }
}

5. Create extension for BottomNavigationView

 fun BottomNavigationView.onItemSelected(function: (Int) -> Unit) {
    setOnNavigationItemSelectedListener { item ->
        for(i in0 until menu.size()) {
            if (menu.getItem(i).itemId == item.itemId) {
                function(i)
            }
        }
        return@setOnNavigationItemSelectedListener true}}

fun BottomNavigationView.onItemReselected(function: (Int) -> Unit) {
    setOnNavigationItemReselectedListener { item ->
        for(i in0 until menu.size()) {
            if(menu.getItem(i).itemId == item.itemId) {
                function(i)
            }
        }
    }
} 

6. And implement these all parts of code in MainActivity

classMainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel
    private lateinit var binding: ActivityMainBinding
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
        binding.bindData(BR.viewmodel, viewModel)

        initViews()
        initObservers()
    }

    private fun initViews() {
        initBottomNavigation()
    }

    private fun initObservers() {
        viewModel.homeItemClickedLD.obs(this) {replaceFragment(R.id.homeContainer, HomeFragment(), false) }
        viewModel.eventsItemClickedLD.obs(this) {replaceFragment(R.id.homeContainer, EventsFragment(), false) }
        viewModel.libraryItemClickedLD.obs(this) {replaceFragment(R.id.homeContainer, LibraryFragment(), false) }
}

    private fun initBottomNavigation() {
        bottomNavigation.onItemSelected {viewModel.onBottomItemChanged(it) }
        bottomNavigation.onItemReselected { }
        replaceFragment(R.id.homeContainer, HomeFragment(), false)
    }
}

Example:

Image for post

So, I hope this article was interesting and useful for you and, of course, if you have any questions or suggestions for improvement, feel free to write me in comments.

If you like this article, that I hope, you will probably like my other articles and find something interesting for you in them here.

Also I have created my own library and you can find it here.

Thanks for reading.