Implementing a Swipeable Bottom Navigation Bar in Android
Most popular Android applications, such as WhatsApp and Instagram, have integrated a swipeable feature with the Bottom Navigation Bar.
In this tutorial, we’ll guide you through the process of implementing a swipeable Bottom Navigation Bar in an Android application using both Kotlin and Java.
1. Declare dependencies
Add this view pager dependency to your project
implementation ("androidx.viewpager2:viewpager2:1.1.0")
2. Design the Layout
In this step, we will create the main layout for our activity, which will include both the ViewPager2
for swiping and the BottomNavigationView
for navigation.
Create the Main Layout
Create a new layout file named activity_main.xml
and add the following XML code:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:menu="@menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
Create Bottom Navigation Menu
Next, define the items for your Bottom Navigation Bar in a new menu resource file named bottom_nav_menu.xml
:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_home"
android:icon="@drawable/ic_home"
android:title="Home" />
<item
android:id="@+id/navigation_dashboard"
android:icon="@drawable/ic_dashboard"
android:title="Dashboard" />
<item
android:id="@+id/navigation_notifications"
android:icon="@drawable/ic_notifications"
android:title="Notifications" />
</menu>
3. Create Fragments for Each Tab
For each tab in the Bottom Navigation Bar, we’ll create a corresponding fragment. In this example, we’ll create three fragments: HomeFragment
, DashboardFragment
, and NotificationsFragment
.
Create Fragment Layouts
Create the layout files for each fragment:
<!-- res/layout/fragment_home.xml -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home Fragment" />
</LinearLayout>
Repeat this process for fragment_dashboard.xml
and fragment_notifications.xml
.
Create Fragment Classes
Next, create the Kotlin or Java classes for each fragment:
In Kotlin:
class HomeFragment : Fragment(R.layout.fragment_home)
class DashboardFragment : Fragment(R.layout.fragment_dashboard)
class NotificationsFragment : Fragment(R.layout.fragment_notifications)
In Java:
public class HomeFragment extends Fragment {
public HomeFragment() {
super(R.layout.fragment_home);
}
}
public class DashboardFragment extends Fragment {
public DashboardFragment() {
super(R.layout.fragment_dashboard);
}
}
public class NotificationsFragment extends Fragment {
public NotificationsFragment() {
super(R.layout.fragment_notifications);
}
}
Step 4: Set Up the ViewPager2 Adapter
To manage the fragments in ViewPager2
, we’ll create a ViewPagerAdapter
. This adapter will handle which fragment to display based on the current tab.
Create the ViewPagerAdapter Class
Create a new Kotlin or Java class named ViewPagerAdapter
.
In Kotlin:
class ViewPagerAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> HomeFragment()
1 -> DashboardFragment()
2 -> NotificationsFragment()
else -> HomeFragment()
}
}
override fun getItemCount(): Int {
return 3 // Number of tabs
}
}
In Java:
public class ViewPagerAdapter extends FragmentStateAdapter {
public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
}
@NonNull
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return new HomeFragment();
case 1:
return new DashboardFragment();
case 2:
return new NotificationsFragment();
default:
return new HomeFragment();
}
}
@Override
public int getItemCount() {
return 3; // Number of tabs
}
}
Step 5: Implement Navigation Logic in the MainActivity
Now, it’s time to link the ViewPager2
and the BottomNavigationView
in the MainActivity
.
Set Up the MainActivity
In your MainActivity
, initialize the ViewPager2
and BottomNavigationView
, and set up their interactions:
In Kotlin:
class MainActivity : AppCompatActivity() {
private lateinit var viewPager: ViewPager2
private lateinit var bottomNavigationView: BottomNavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPager = findViewById(R.id.viewPager)
bottomNavigationView = findViewById(R.id.bottom_navigation)
val adapter = ViewPagerAdapter(this)
viewPager.adapter = adapter
// Handle swipe between pages
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
bottomNavigationView.menu.getItem(position).isChecked = true
}
})
// Handle click on BottomNavigationView items
bottomNavigationView.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> viewPager.currentItem = 0
R.id.navigation_dashboard -> viewPager.currentItem = 1
R.id.navigation_notifications -> viewPager.currentItem = 2
}
true
}
}
}
In Java:
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager;
private BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.viewPager);
bottomNavigationView = findViewById(R.id.bottom_navigation);
ViewPagerAdapter adapter = new ViewPagerAdapter(this);
viewPager.setAdapter(adapter);
// Handle swipe between pages
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
bottomNavigationView.getMenu().getItem(position).setChecked(true);
}
});
// Handle click on BottomNavigationView items
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.navigation_home:
viewPager.setCurrentItem(0);
break;
case R.id.navigation_dashboard:
viewPager.setCurrentItem(1);
break;
case R.id.navigation_notifications:
viewPager.setCurrentItem(2);
break;
}
return true;
});
}
}