
BottomAppBar是Google I / O 2018引入的新的Android Material组件之一。 通过将导航抽屉和应用程序菜单移动到屏幕底部,BottomAppBar将从根本上改变Android应用程序的外观。
在有关BottomAppBar的系列文章的第一部分和第二部分中,我们会见了BottomAppBar并讨论了其属性。 我们还解释了如何在BottomAppBar中实现导航抽屉和应用程序菜单。
举止
根据材料设计,应用程序组件不是静态的。 它们可以移动或变换,即 有某种行为 物料设计也形成了这种行为的框架。 在本文中,我们将讨论BottomAppBar的推荐行为的实现细节,该细节在BottomAppBar的指南页面上提供 。
布局图
第一条准则描述了BottomAppBar的布局。 建议如下:
对于具有不同含义的应用程序屏幕,可以在BottomAppBar中更改布局和菜单项集。 例如,您可以根据最适合特定屏幕的内容显示更多或更少的菜单项。

根据此指南,建议在主屏幕上使用BottomAppBar布局,该布局显示几个菜单项和一个居中的FAB(浮动操作按钮)。 在辅助屏幕 (从主屏幕过渡到辅助屏幕)上 ,BottomAppBar布局应包含一个右对齐的FAB和几个其他菜单项。 这两个屏幕之间的转换必须正确执行。 顶部的Gif演示了此指南。
现在让我们看看如何实现这种行为。 在每个屏幕的菜单的res/menu
文件夹中,我们有两个xml文件:
<?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>
当在屏幕之间进行转换时,例如,在本例中,通过按“切换屏幕”按钮,BottomAppBar的布局(包括菜单和FAB)应更改。 这是BottomAppBar布局的这种行为的基本代码:
// 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)
如果要进行动画过渡,则需要其他代码。 您可以研究本文结尾处附带的源代码,在其中您可以找到动画。
卷动
滚动是BottomAppBar等组件的重要行为触发器。 在“材料设计准则”页面上,对于这种情况,建议采取以下行为:
滚动时,BottomAppBar可能会出现或消失:
-向下滚动隐藏BottomAppBar。 如果具有FAB,它将与面板断开连接并保留在屏幕上。
-向上滚动显示BottomAppBar,然后将其重新附加到FAB。
下面是滚动时BottomAppBar行为的演示。

若要使用此行为,BottomAppBar和FAB必须是CoordinatorLayout的直接子代。 然后,我们启用hideOnScroll并设置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"/>
这足以实现BottomAppBar的这种行为。
高程
“材料设计”世界中的每个组件的海拔都类似于我们的物理世界。 在BottomAppBar处,高程为8dp ,而屏幕本身的内容将上升为0dp 。 静态状态下的FAB上升12dp 。 我们将在本文中回顾的两个组件Navigation Drawer和Snackbar分别提高了16dp和6dp 。
通常,Snackbar是用于通知从屏幕底部弹出的用户的组件。 但是,如果屏幕上有一个BottomAppBar或Navigation Drawer,则Snackbar的行为应该改变。 在这种情况下,小吃店应显示在下部组件的上方 。 这是一个演示和相关代码以实现:

private fun displayMaterialSnackBar() { val marginSide = 0 val marginBottom = 550 val snackbar = Snackbar.make( coordinatorLayout2, "FAB Clicked", Snackbar.LENGTH_LONG ).setAction("UNDO") { }
正如我们已经提到的,导航抽屉增加了16dp ,这意味着-根据指南-
从BottomAppBar掉出来的菜单(例如导航抽屉)作为模式窗口打开,比BottomAppBar本身高一层。
以下是导航抽屉的实现:

导航抽屉是模式窗口 ,因此遵循上面的实现规则。
实现此行为的详细信息如下。 在res/menu
文件夹中,必须创建导航视图的xml菜单文件,该文件将在导航抽屉中使用:
<?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>
然后,应使用导航抽屉为该片段创建一个布局文件:
<?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>
该布局文件包含导航视图和其他组成导航抽屉布局的组件。 要创建此布局,我们需要一个扩展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 ->
当您单击导航抽屉图标时,将创建此片段的一个实例,该实例显示为模式窗口:
override fun onOptionsItemSelected(item: MenuItem?): Boolean { when (item!!.itemId) { android.R.id.home -> { val bottomNavDrawerFragment = BottomNavigationDrawerFragment() bottomNavDrawerFragment.show(supportFragmentManager, bottomNavDrawerFragment.tag) } } return true }
本文总结了有关BottomAppBar的系列文章。 您可以在Github上找到本文的源代码。 发表评论并提出问题。
←BottomAppBar的实现。 第1部分:Android的材料组件
←BottomAppBar的实现。 第2部分:菜单和导航抽屉控件