导航抽屉打开时如何让Floating Action Button可聚焦可点击并控制显隐
实现方案及错误修复
核心问题排查&修复
1. 布局层级错误修复
DrawerLayout的官方要求子View顺序为:第一个子View是主界面内容,后续子View是抽屉视图,你当前把NavigationView放在主内容前面,导致抽屉永远覆盖在主内容之上,即使调用bringToFront()也无法让主内容里的FAB获得焦点。
如果需要FAB悬浮在所有视图最上层(包括抽屉),建议直接将FAB放到DrawerLayout的最外层作为最后一个子节点,修改后布局代码如下:
<?xml version="1.0" encoding="utf-8"?> <androidx.drawerlayout.widget.DrawerLayout 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" android:id="@+id/drawer_layout"> <!-- 第一个子View:主内容布局 --> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 你的主界面其他控件都放这里 --> </androidx.constraintlayout.widget.ConstraintLayout> <!-- 第二个子View:抽屉视图 --> <com.google.android.material.navigation.NavigationView android:id="@+id/drawerNavigationView" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/navigation_drawer_header" app:menu="@menu/navigation_drawer_menu" android:fitsSystemWindows="true" app:insetForeground="@android:color/transparent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="bottom" android:paddingLeft="20dp" android:paddingBottom="20dp" android:paddingTop="40dp"> <ImageView android:id="@+id/logoutNavigationDrawer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src ="@drawable/icon_logout" android:layout_centerVertical="true"/> <TextView android:id="@+id/logoutTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/orangeText" android:paddingLeft="14dp" android:textSize="16sp" android:fontFamily="@font/century_gothic_bold" android:text="Log out" android:layout_toEndOf="@+id/logoutNavigationDrawer" android:layout_toRightOf="@+id/logoutNavigationDrawer" android:layout_centerVertical="true"/> </RelativeLayout> </com.google.android.material.navigation.NavigationView> <!-- 最后一个子View:悬浮FAB,默认在最上层 --> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/emergencyCallFAB" android:layout_width="wrap_content" app:tint="@color/white" android:layout_height="wrap_content" android:src="@drawable/emergency_call_button_round" app:backgroundTint="@color/red" android:layout_marginEnd="50dp" android:layout_marginBottom="50dp" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> </androidx.drawerlayout.widget.DrawerLayout>
注意:这里给FAB加了默认
android:visibility="gone",避免初始化时显示。
2. DrawerToggle回调错误修复
你当前onDrawerOpened方法内错误调用了super.onDrawerClosed(drawerView),这会触发抽屉关闭逻辑,是直接导致崩溃的核心原因,修正后的DrawerToggle代码如下:
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(Location.this, drawerLayout, R.string.navigation_drawer_open, R.string.navigation_drawer_close){ @Override public void onDrawerOpened(View drawerView){ // 修正:调用对应的super方法 super.onDrawerOpened(drawerView); emergenyCallFABBtn.setVisibility(View.VISIBLE); } @Override public void onDrawerSlide(View drawerView, float slideOffset) { super.onDrawerSlide(drawerView, slideOffset); emergenyCallFABBtn.setAlpha(slideOffset); // 滑动偏移大于0就显示,避免隐藏状态下有透明度变化 if(slideOffset>0 && emergenyCallFABBtn.getVisibility()!=View.VISIBLE){ emergenyCallFABBtn.setVisibility(View.VISIBLE); } } @Override public void onDrawerClosed(View view){ super.onDrawerClosed(view); emergenyCallFABBtn.setVisibility(View.GONE); } };
修正后不需要再调用
bringToFront(),因为布局已经保证FAB在最上层,点击事件可以直接响应。
3. 冗余代码删除&触摸事件修正
你当前的dispatchTouchEvent属于冗余代码,布局层级修正后FAB可以直接响应点击,不需要手动判断触摸区域。如果要保留该方法,需要将坐标判断改为屏幕坐标,避免匹配错误:
@Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { if (drawerLayout.isDrawerOpen(navigationView) && emergenyCallFABBtn.getVisibility() == View.VISIBLE) { int[] contentLocation = new int[2]; emergenyCallFABBtn.getLocationOnScreen(contentLocation); Rect rect = new Rect(contentLocation[0], contentLocation[1], contentLocation[0] + emergenyCallFABBtn.getWidth(), contentLocation[1] + emergenyCallFABBtn.getHeight()); // 修正:用getRawX、getRawY获取屏幕坐标匹配 if ((rect.contains((int) event.getRawX(), (int) event.getRawY()))) { emergenyCallFABBtn.performClick(); return true; } } } return super.dispatchTouchEvent(event); }
注意统一FAB的变量名,避免因变量名不一致导致空指针异常。
内容的提问来源于stack exchange,提问作者new_programming_student
相关产品推荐
相关产品推荐

