The purpose of this code base is to explore the different ways that you can add a Bottom Navigation Bar to an app. The two different implementations that are used in this codebase is Jetpack's Navigation Componenets add the OnNavigationItemSelectedListener method.
The naming of the this UI componenet is inconsistent across the documentaion and APIs (unless I am missing something). It is referred to as BottomNavigationView, but as it is also a menu, it can be referred to as BottomNavigatioMenu. This is noticeable in the XML files you work with to build out this functionality (app:menu, header type).
You need to create an XML file for the bottom navigation view. This will be saved into a menu folder in your file directory. The XML file contains items types that corresponds to the tabs along the view.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/home"
android:title="Home"
app:showAsAction="always"
android:orderInCategory="1"
android:icon="@drawable/nav_bar_home_foreground" />
<item
android:id="@+id/settings"
android:title="Settings"
app:showAsAction="always"
android:orderInCategory="2"
android:icon="@drawable/nav_bar_settings_foreground" />
</menu>
Once you have created your bottom navigation view xml file, you can implement it into your Activities XMLs as you would any other view element.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="75dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_nav_menu"/>
</androidx.constraintlayout.widget.ConstraintLayout>
You are able to use the Jetpack Navigation Components to manage your BottomNavigationView functionality. Jetpack Navigation Graphs is destination and fragment focused. In your MainActivity, you will need a FragmentContainerView that will hold the fragments the user will navigation through. There are three properties that the Navigation Graph depends on in order to function correctly.
android:name="androidx.navigation.fragment.NavHostFragment" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph"
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="75dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_nav_menu"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Navigation is handeled using a NavController. This object manages app navigation with a NavHost (each host as its own controller). You need to get the navcontroller for the host that you are interacting with (findFragmentById). As we are using a BottomNavigationView, we need to setup the navigationController with the bottomNavigationView.
NavHostFragment navHostFragment =
(NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
NavigationUI.setupWithNavController(bottomNavigationView, navHostFragment.getNavController());
You setup your Navigation Graph as you would without a BottomNavigationView. Ensure that your IDs are consistent across the fragmentId (in the navgraph), and bottom_nav_menu items id.
The more traditional way (I think) is to implement a BottomNavigationView using the OnNavigationItemSelectedListener. You create and implement your bottom_nav_menu.xml and your FragmentContainer/FrameLayout as you usually would. This approach uses the FragmentManager and FragmentTransaction objects to manage adding and replacing fragments based on user interaction.
package com.example.bottomnavigationjetpack;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.NavigationUI;
import android.app.Fragment;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationView;
public class MainActivity extends AppCompatActivity {
HomeFragment homeFragment;
SettingsFragment settingsFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
homeFragment = new HomeFragment();
settingsFragment = new SettingsFragment();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
switch (item.getItemId()) {
case R.id.home:
fragmentTransaction.replace(R.id.flFragment, homeFragment);
fragmentTransaction.commit();
break;
case R.id.settings:
fragmentTransaction.replace(R.id.flFragment, settingsFragment);
fragmentTransaction.commit();
break;
}
return false;
}
});
}
}