BottomAppBar实现。 第3部分:Android行为

BottomAppBar实现。第3部分:Android行为


BottomAppBarGoogle 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


若要使用此行为,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分别提高了16dp6dp


通常,Snackbar是用于通知从屏幕底部弹出的用户的组件。 但是,如果屏幕上有一个BottomAppBar或Navigation Drawer,则Snackbar的行为应该改变。 在这种情况下,小吃店应显示下部组件的上方 。 这是一个演示和相关代码以实现:


小吃店和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() } 

正如我们已经提到的,导航抽屉增加了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 -> // 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 } } } 

当您单击导航抽屉图标时,将创建此片段的一个实例,该实例显示为模式窗口:


 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部分:菜单和导航抽屉控件

Source: https://habr.com/ru/post/zh-CN422445/


All Articles