Google I/O ‘18 came up with many exciting new stuff, one of them was the updated Material Design Components. The new BottomAppBar is placed at the bottom of app window in contrary to Toolbar which is located at the upper side of app window. It puts more focus on features, increases engagement, and visually anchors the UI.
So today we are going to learn how to implement BottomAppBar.
1. Create a new project in Android Studio by navigating to File ⇒ New ⇒ New Project and fill required details. By default my activity is MainActivity.java.
2. First of all add the material components dependency in app level build.gradle.
1 2 |
//material components dependency implementation 'com.google.android.material:material:1.1.0-alpha02' |
Note : Currently this dependency is in alpha so make sure you update dependency whenever new update is available.
In case you get some error like below while building:
then add the below mentioned two lines of code in gradle.properties.
1 2 |
android.useAndroidX=true android.enableJetifier=true |
3. Create activity_main.xml and add the following code. Here we have taken BottomAppBar and FloatingActionButton.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/coordinatorLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/content_main" /> <!-- Bottom bar --> <com.google.android.material.bottomappbar.BottomAppBar android:id="@+id/bar" style="@style/Widget.MaterialComponents.BottomAppBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:backgroundTint="@color/colorPrimary" app:fabAlignmentMode="center" app:fabCradleMargin="10dp" app:fabCradleRoundedCornerRadius="10dp" app:fabCradleVerticalOffset="5dp" app:hideOnScroll="true" app:navigationIcon="@drawable/ic_menu_white_24dp" /> <!-- Floating Action button --> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:tint="@android:color/white" app:fabSize="normal" app:layout_anchor="@id/bar" app:srcCompat="@drawable/ic_add_black_24dp" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> |
There are few attributes of BottomBarApp as follows:
NOTE : Make sure you add style=”@style/Widget.MaterialComponents.BottomAppBar” to BottomAppBar.
Below is the remaining layout of content_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/content_coordinator_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:showIn="@layout/activity_main"> <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" android:onClick="toggleFabMode" android:text="Toggle FAB Mode" android:textColor="@android:color/white" android:textSize="15sp" /> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="20dp" android:lineSpacingExtra="4dp" android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquam ut porttitor leo a diam sollicitudin tempor id. Pretium vulputate sapien nec sagittis aliquam malesuada bibendum. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Vitae et leo duis ut diam quam nulla porttitor massa. Urna condimentum mattis pellentesque id nibh tortor id aliquet lectus. Nunc sed blandit libero volutpat sed cras. In hendrerit gravida rutrum quisque non tellus orci ac auctor. Lectus arcu bibendum at varius vel pharetra. Posuere morbi leo urna molestie at elementum eu facilisis sed. Urna cursus eget nunc scelerisque viverra mauris. Blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada. At erat pellentesque adipiscing commodo. Praesent tristique magna sit amet purus. Eget felis eget nunc lobortis mattis aliquam. Egestas sed sed risus pretium quam vulputate. Convallis aenean et tortor at risus viverra. Ut diam quam nulla porttitor massa id neque aliquam. Purus sit amet volutpat consequat mauris nunc congue nisi. Nibh nisl condimentum id venenatis a condimentum vitae sapien pellentesque. Suscipit adipiscing bibendum est ultricies integer quis auctor elit. Semper quis lectus nulla at volutpat diam ut. Dolor sed viverra ipsum nunc aliquet bibendum enim facilisis. Sit amet massa vitae tortor condimentum. Condimentum vitae sapien pellentesque habitant morbi tristique. Feugiat sed lectus vestibulum mattis. Facilisis mauris sit amet massa vitae tortor condimentum. Malesuada pellentesque elit eget gravida cum sociis natoque penatibus et. Pellentesque diam volutpat commodo sed egestas egestas. Elementum tempus egestas sed sed. Nibh tortor id aliquet lectus proin nibh nisl condimentum." android:textColor="@android:color/black" android:textSize="15sp" /> </LinearLayout> </androidx.core.widget.NestedScrollView> </androidx.coordinatorlayout.widget.CoordinatorLayout> |
4. Now open your MainActivity.java class and place the below code into it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
package com.bottom.appbar.demo; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; import com.google.android.material.bottomappbar.BottomAppBar; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; public class MainActivity extends AppCompatActivity { private BottomAppBar bottomAppBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setUpBottomAppBar(); //click event over FAB findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "FAB Clicked.", Toast.LENGTH_SHORT).show(); } }); } /** * set up Bottom Bar */ private void setUpBottomAppBar() { //find id bottomAppBar = findViewById(R.id.bar); //set bottom bar to Action bar as it is similar like Toolbar setSupportActionBar(bottomAppBar); //click event over Bottom bar menu item bottomAppBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.action_notification: Toast.makeText(MainActivity.this, "Notification clicked.", Toast.LENGTH_SHORT).show(); break; } return false; } }); //click event over navigation menu like back arrow or hamburger icon bottomAppBar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //open bottom sheet BottomSheetDialogFragment bottomSheetDialogFragment = BottomSheetNavigationFragment.newInstance(); bottomSheetDialogFragment.show(getSupportFragmentManager(), "Bottom Sheet Dialog Fragment"); } }); } //Inflate menu to bottom bar @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_notification: break; } return super.onOptionsItemSelected(item); } /** * method to toggle fab mode * * @param view */ public void toggleFabMode(View view) { //check the fab alignment mode and toggle accordingly if (bottomAppBar.getFabAlignmentMode() == BottomAppBar.FAB_ALIGNMENT_MODE_END) { bottomAppBar.setFabAlignmentMode(BottomAppBar.FAB_ALIGNMENT_MODE_CENTER); } else { bottomAppBar.setFabAlignmentMode(BottomAppBar.FAB_ALIGNMENT_MODE_END); } } } |
The above class have some features as follows:
Handling Menu Options : There are two ways to handle menu options. The first way is to directly call setOnMenuItemClickListener(OnMenuItemClickListener) and to handle the menu options in the callback:
1 2 3 4 5 6 7 8 9 10 |
BottomAppBar bottomAppBar = findViewById(R.id.bar); //click event over Bottom bar menu item bottomAppBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { //do your stuff return true; } }); |
The other way is to call setSupportActionBar() on the BottomAppBar. This will set up the menu callbacks in a similar way to Toolbar which hooks into Activity#onCreateOptionsMenu() and Activity#onOptionsItemSelected(). This makes it easier to transition from a Toolbar which was set as the action bar to a BottomAppBar. This will also allow you to handle the navigation item click by checking if the menu item id is android.R.id.home.
1 2 3 4 |
BottomAppBar bottomAppBar = findViewById(R.id.bar); //set bottom bar to Action bar as it is similar like Toolbar setSupportActionBar(bottomAppBar); |
Handling Navigation Item Click: If you use setSupportActionBar() to set up the BottomAppBar you can handle the navigation menu click by checking if the menu item id is android.R.id.home. The other option is to call setNavigationOnClickListener(OnClickListener):
1 2 3 4 5 6 7 8 9 |
BottomAppBar bottomAppBar = findViewById(R.id.bar); //click event over navigation menu like back arrow or hamburger icon bottomAppBar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //do your stuff } }); |
Toggling FAB Alignment Mode : If you want to change/toggle FAB alignment mode from Center to End or Vice-Versa. You can do by using below code:
1 2 3 4 5 |
if (bottomAppBar.getFabAlignmentMode() == BottomAppBar.FAB_ALIGNMENT_MODE_END) { bottomAppBar.setFabAlignmentMode(BottomAppBar.FAB_ALIGNMENT_MODE_CENTER); } else { bottomAppBar.setFabAlignmentMode(BottomAppBar.FAB_ALIGNMENT_MODE_END); } |
5. Since we have added hamburger icon to open Navigation View. So let’s see how to implement NavigationView in BottomAppBar. We will implement it with the help of BottomSheet. If you are not aware of BottomSheet then check here. Let’s create an xml naming bottom_navigation_drawer.xml and place the below code to it. In this xml we have created one header and one NavigationView.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/navigation_view_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- navigation header layout --> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/profile_image" android:layout_width="48dp" android:layout_height="48dp" android:layout_centerVertical="true" android:layout_marginLeft="16dp" app:srcCompat="@drawable/ic_account_circle_black_24dp" /> <TextView android:id="@+id/user_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="12dp" android:layout_marginTop="16dp" android:layout_toLeftOf="@+id/close_image_view" android:layout_toRightOf="@+id/profile_image" android:text="Dr. Droid" android:textColor="@android:color/black" android:textSize="18sp" android:textStyle="bold" /> <TextView android:id="@+id/user_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/user_name" android:layout_marginLeft="12dp" android:layout_marginTop="2dp" android:layout_toLeftOf="@+id/close_image_view" android:layout_toRightOf="@+id/profile_image" android:textColor="@android:color/black" /> <ImageView android:id="@+id/close_image_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:padding="16dp" android:visibility="gone" app:srcCompat="@drawable/ic_close_black_24dp" /> <View android:id="@+id/divider_one" android:layout_width="match_parent" android:layout_height="2dip" android:layout_below="@+id/user_email" android:layout_marginTop="15dp" android:background="#447e7e7e" /> </RelativeLayout> <!-- navigation view --> <com.google.android.material.navigation.NavigationView android:id="@+id/navigation_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="4dp" app:menu="@menu/bottom_navigation_menu" /> </LinearLayout> |
6. For NavigationView create a menu under res/menu naming bottom_navigation_menu.xml and place the below menus to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<?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"> <group android:checkableBehavior="none"> <item android:id="@+id/nav01" android:icon="@drawable/ic_account_box_black_24dp" android:title="Item 1" /> <item android:id="@+id/nav02" android:icon="@drawable/ic_assessment_black_24dp" android:title="Item 2" /> <item android:id="@+id/nav03" android:icon="@drawable/ic_assignment_black_24dp" android:title="Item 3" /> <item android:id="@+id/nav04" android:icon="@drawable/ic_attachment_black_24dp" android:title="Item 4" /> <item android:id="@+id/nav05" android:icon="@drawable/ic_bookmark_black_24dp" android:title="Item 5" /> <item android:id="@+id/nav06" android:icon="@drawable/ic_call_black_24dp" android:title="Item 6" /> <item android:id="@+id/nav07" android:icon="@drawable/ic_description_black_24dp" android:title="Item 7" /> <item android:id="@+id/nav08" android:icon="@drawable/ic_dashboard_black_24dp" android:title="Item 8" /> <item android:id="@+id/nav09" android:icon="@drawable/ic_event_available_black_24dp" android:title="Item 9" /> <item android:id="@+id/nav10" android:icon="@drawable/ic_forum_black_24dp" android:title="Item 10" /> <item android:id="@+id/nav11" android:icon="@drawable/ic_local_post_office_black_24dp" android:title="Item 11" /> <item android:id="@+id/nav12" android:icon="@drawable/ic_work_black_24dp" android:title="Item 12" /> <item android:id="@+id/nav13" android:icon="@drawable/ic_watch_later_black_24dp" android:title="Item 13" /> <item android:id="@+id/nav14" android:icon="@drawable/ic_sync_black_24dp" android:title="Item 14" /> <item android:id="@+id/nav15" android:icon="@drawable/ic_info_black_24dp" android:title="Item 15" /> <item android:id="@+id/nav16" android:icon="@drawable/ic_power_settings_new_black_24dp" android:title="Item 16" /> </group> </menu> |
7. Now create a java class naming BottomSheetNavigationFragment.java and place the below code into it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
package com.bottom.appbar.demo; import android.annotation.SuppressLint; import android.app.Dialog; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.navigation.NavigationView; import androidx.annotation.NonNull; import androidx.coordinatorlayout.widget.CoordinatorLayout; /** * Created by sonu on 17:07, 10/01/19 * Copyright (c) 2019 . All rights reserved. */ public class BottomSheetNavigationFragment extends BottomSheetDialogFragment { public static BottomSheetNavigationFragment newInstance() { Bundle args = new Bundle(); BottomSheetNavigationFragment fragment = new BottomSheetNavigationFragment(); fragment.setArguments(args); return fragment; } //Bottom Sheet Callback private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { dismiss(); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { //check the slide offset and change the visibility of close button if (slideOffset > 0.5) { closeButton.setVisibility(View.VISIBLE); } else { closeButton.setVisibility(View.GONE); } } }; private ImageView closeButton; @SuppressLint("RestrictedApi") @Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); //Get the content View View contentView = View.inflate(getContext(), R.layout.bottom_navigation_drawer, null); dialog.setContentView(contentView); NavigationView navigationView = contentView.findViewById(R.id.navigation_view); //implement navigation menu item click event navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.nav01: break; } return false; } }); closeButton = contentView.findViewById(R.id.close_image_view); closeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //dismiss bottom sheet dismiss(); } }); //Set the coordinator layout behavior CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams(); CoordinatorLayout.Behavior behavior = params.getBehavior(); //Set callback if (behavior instanceof BottomSheetBehavior) { ((BottomSheetBehavior) behavior).setBottomSheetCallback(mBottomSheetBehaviorCallback); } } } |
8. We have used menu for BottomBar too so below is the menu naming main_menu.xml for BottomBar.
1 2 3 4 5 6 7 8 9 |
<?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/action_notification" app:showAsAction="always" android:icon="@drawable/ic_notifications_white_24dp" android:title="@string/notification" /> </menu> |
9. Don’t forgot to change your base theme into MaterialComponents according to your requirement.
1 2 3 4 5 6 7 8 9 10 11 |
<resources> <!-- Base application theme. Set the material components theme--> <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources> |
10. Finally, all done run your code.
Thanks.
Subscribe to us and get the latest news.
4 Comments
Armando Santos
Thursday, March 14th, 2019If I want to implement Behavior in this example, when I move to fragment 2, the animation transition does not work, why?
Dr. Droid
Sunday, March 17th, 2019Hi Armando,
Which animation won’t work can you clarify?
Thanks
Monoo M
Wednesday, August 12th, 2020That was a great tutorial. But I would rather die instead of download the source.
Please fix that button. And no I am not using any adblocker.
Thanks.
Dr. Droid
Friday, August 14th, 2020Hi Monoo,
Thank you for pointing out the download button issue. It is fixed now.
Thanks