📜 ⬆️ ⬇️

BottomAppBar implementation. Part 3: Behaviors for Android

BottomAppBar implementation. Part 3: Behaviors for Android


BottomAppBar is one of the new Android Material components that were introduced on Google I / O 2018 . By moving the Navigation Drawer and the application menu to the bottom of the screen, the BottomAppBar radically changes the look of Android applications.


In the first and second parts of our series on BottomAppBar, we met BottomAppBar and discussed its attributes. We also explained how to implement the Navigation Drawer and the application menu within the BottomAppBar.


Behavior


According to Material Design, application components are not static. They can move or transform, i.e. have some kind of behavior. Material Design also forms some framework for this behavior. In this article we will discuss the details of the implementation of the recommended behavior for BottomAppBar, which is presented on the guidelines page for BottomAppBar .


Layout


The first guideline describes the BottomAppBar layout. Here is what is offered :


For different within the application screens, you can change the layout and set of menu items in the BottomAppBar. For example, you can display more or less menu items depending on what is best for a particular screen.

Layout guideline


Based on this guideline, on the main screens it is recommended to use the BottomAppBar layout, which shows several menu items and the FAB (Floating Action Button) centered menu. On secondary screens , transition to which is carried out from the main, the BottomAppBar layout should consist of a right-aligned FAB and several additional items in the menu. Transitions between these two screens must be performed properly. Gif on top shows this guideline.


Now let's see how this behavior can be implemented. We have two xml files in the res/menu folder for the menu of each screen:


 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/app_bar_search" android:icon="@drawable/baseline_search_white_24" android:title="@string/action_search" app:showAsAction="ifRoom"/> </menu> 

 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/app_bar_mail" android:icon="@drawable/baseline_mail_white_24" android:title="@string/action_mail" app:showAsAction="ifRoom"/> <item android:id="@+id/app_bar_delete" android:icon="@drawable/baseline_delete_white_24" android:title="@string/action_delete" app:showAsAction="ifRoom"/> <item android:id="@+id/app_bar_archieve" android:icon="@drawable/baseline_archive_white_24" android:title="@string/action_archieve" app:showAsAction="ifRoom"/> </menu> 

When there is a transition between the screens, for example, by pressing the TOGGLE SCREEN button in our case, the BottomAppBar layout, including the menu and the FAB, should change. Here is the base code for this behavior of the BottomAppBar layout:


 // Hide navigation drawer icon bottom_app_bar.navigationIcon = null // Move FAB from the center of BottomAppBar to the end of it bottom_app_bar.fabAlignmentMode = BottomAppBar.FAB_ALIGNMENT_MODE_END // Replace the action menu bottom_app_bar.replaceMenu(bottomappbar_menu_secondary) // Change FAB icon fab?.setImageDrawable(baseline_reply_white_24) 

If you want to make animated transitions, you need additional code. You can study the source code attached at the end of this article in which you will find the animation.


Scrolling


Scrolling is an important behavior trigger for components such as BottomAppBar. The following behavior is recommended for this case on the Material Design guidelines page:


When scrolling, BottomAppBar may appear or disappear:
- Scrolling down hides the BottomAppBar. If it had a FAB, it disconnects from the panel and remains on the screen.
- Scrolling up shows BottomAppBar and reattaches it to the FAB, if it was there.

Below is a demonstration of the behavior of BottomAppBar when scrolling.


Scrolling and BottomAppBar


To use this behavior, BottomAppBar and FAB must be direct children of CoordinatorLayout . Then we enable hideOnScroll and set the scroll flags for the BottomAppBar:


 <com.google.android.material.bottomappbar.BottomAppBar android:id="@+id/bottom_app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:fabAlignmentMode="center" app:hideOnScroll="true" app:layout_scrollFlags="scroll|enterAlways"/> 

This is quite enough to implement this behavior BottomAppBar.


Elevation


Every component in the Material Design world has an elevation similar to our physical world. For BottomAppBar, the elevation is 8dp , and the actual content of the screen is 0dp . FAB in static state rises to 12dp . The two components that we will recall in this article, Navigation Drawer and Snackbar, are 16dp and 6dp respectively.


Snackbar is typically a user notification component that pops up from the bottom of the screen. But if there is a BottomAppBar or Navigation Drawer on the screen, the Snackbar behavior should change. In these cases, the Snackbar should be shown above the bottom components. Here is a demonstration and corresponding code for implementation:


Snackbar and BottomAppBar


 private fun displayMaterialSnackBar() { val marginSide = 0 val marginBottom = 550 val snackbar = Snackbar.make( coordinatorLayout2, "FAB Clicked", Snackbar.LENGTH_LONG ).setAction("UNDO") { } // Changing message text color snackbar.setActionTextColor(ContextCompat.getColor(this, R.color.colorSnackbarButton)) val snackbarView = snackbar.view val params = snackbarView.layoutParams as CoordinatorLayout.LayoutParams params.setMargins( params.leftMargin + marginSide, params.topMargin, params.rightMargin + marginSide, params.bottomMargin + marginBottom ) snackbarView.layoutParams = params snackbar.show() } 

As we mentioned, the Navigation Drawer rises to 16dp , which means - according to the guideline -


Menus that fall out of BottomAppBar (for example, Navigation Drawer) open as modal windows a level higher than BottomAppBar itself.

The following is the implementation of our Navigation Drawer:


Navigation Drawer Behavior


Navigation Drawer is a modal window and therefore follows the above implementation rule.


Details of the implementation of this behavior are as follows. In the res/menu folder, you need to create an XML menu file for the Navigation View , which will be used in the Navigation Drawer:


 <?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/nav1" android:icon="@drawable/baseline_mail_white_24" android:title="@string/nav_item1" /> <item android:id="@+id/nav2" android:icon="@drawable/baseline_bookmark_white_24" android:title="@string/nav_item2" /> <item android:id="@+id/nav3" android:icon="@drawable/baseline_message_white_24" android:title="@string/nav_item3" /> <item android:id="@+id/nav4" android:icon="@drawable/baseline_note_white_24" android:title="@string/nav_item4" /> <item android:id="@+id/nav5" android:icon="@drawable/baseline_location_on_white_24" android:title="@string/nav_item5" /> <item android:id="@+id/nav6" android:icon="@drawable/baseline_sync_white_24" android:title="@string/nav_item6" /> <item android:id="@+id/nav7" android:icon="@drawable/baseline_cloud_upload_white_24" android:title="@string/nav_item7" /> <item android:id="@+id/nav8" android:icon="@drawable/baseline_favorite_white_24" android:title="@string/nav_item8" /> <item android:id="@+id/nav9" android:icon="@drawable/baseline_chrome_reader_mode_white_24" android:title="@string/nav_item9" /> <item android:id="@+id/nav10" android:icon="@drawable/baseline_select_all_white_24" android:title="@string/nav_item10" /> <item android:id="@+id/nav11" android:icon="@drawable/baseline_sort_white_24" android:title="@string/nav_item11" /> <item android:id="@+id/nav12" android:icon="@drawable/baseline_access_time_white_24" android:title="@string/nav_item12" /> <item android:id="@+id/nav13" android:icon="@drawable/baseline_data_usage_white_24" android:title="@string/nav_item13" /> </group> </menu> 

Then a layout file should be created for the fragment using the Navigation Drawer:


 <?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:id="@+id/navigation_view_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:behavior_hideable="true" app:layout_behavior="@string/bottom_sheet_behavior"> <com.google.android.material.navigation.NavigationView android:id="@+id/navigation_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginTop="4dp" android:paddingBottom="40dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/view2" app:menu="@menu/bottom_nav_drawer_menu" app:theme="@style/NavigationDrawerStyle" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginTop="16dp" android:fontFamily="@font/rubik_medium" android:text="@string/bottom_sheet_name" android:textColor="@color/colorAccent" android:textSize="18sp" android:textStyle="bold" app:layout_constraintStart_toEndOf="@+id/imageView" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:text="@string/bottom_sheet_email" android:textColor="@color/colorAccent" app:layout_constraintStart_toStartOf="@+id/textView" app:layout_constraintTop_toBottomOf="@+id/textView" /> <ImageView android:id="@+id/imageView" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="24dp" android:background="@drawable/baseline_account_circle_black_48" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/textView" /> <View android:id="@+id/view2" android:layout_width="match_parent" android:layout_height="2dip" android:layout_marginTop="15dp" android:background="#447e7e7e" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView2" /> <ImageView android:id="@+id/close_imageview" android:layout_width="24dp" android:layout_height="24dp" android:layout_marginTop="8dp" android:layout_marginEnd="16dp" android:layout_marginBottom="8dp" android:background="@drawable/baseline_close_black_24" android:visibility="gone" app:layout_constraintBottom_toBottomOf="@+id/textView2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/textView" /> </androidx.constraintlayout.widget.ConstraintLayout> 

This layout file contains the Navigation View and other components that form the layout for the Navigation Drawer. To create this layout, we need a fragment class that extends the BottomSheetDialogFragment:


 class BottomNavigationDrawerFragment: BottomSheetDialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_bottom_navigation_drawer, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) navigation_view.setNavigationItemSelectedListener { menuItem -> // Bottom Navigation Drawer menu item clicks when (menuItem.itemId) { // R.id.nav1 -> context!!.toast(getString(R.string.nav1_clicked)) } // Add code here to update the UI based on the item selected // For example, swap UI fragments here true } } } 

When you click on the icon Navigation Drawer, an instance of this fragment is created, which is shown as a modal window:


 override fun onOptionsItemSelected(item: MenuItem?): Boolean { when (item!!.itemId) { android.R.id.home -> { val bottomNavDrawerFragment = BottomNavigationDrawerFragment() bottomNavDrawerFragment.show(supportFragmentManager, bottomNavDrawerFragment.tag) } } return true } 

This article completes our series of articles on BottomAppBar. You can find the source code for this article on Github . Comment and ask questions.


← BottomAppBar implementation. Part 1: Material Components for Android
← BottomAppBar implementation. Part 2: Navigation Drawer Menu and Control


')

Source: https://habr.com/ru/post/422445/


All Articles