Android:fitsSystemWindow导致BottomNavigationView内边距异常,求解决方案
问题现象
当根布局ConstraintLayout设置android:fitsSystemWindows="true"时,BottomNavigationView底部出现额外空白内边距,整体上移;设置为false时,BottomNavigationView紧贴屏幕底部,但Toolbar可能被状态栏遮挡。
布局代码
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/parent" android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="@dimen/dp56" android:background="@color/colorWhite" android:elevation="@dimen/dp5" android:minHeight="?attr/actionBarSize" app:layout_constraintBottom_toTopOf="@id/nav_host_fragment" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" app:titleTextColor="@android:color/black"> <TextView android:id="@+id/toolBarTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@color/colorBlack" android:textSize="@dimen/text16" /> </androidx.appcompat.widget.Toolbar> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintBottom_toTopOf="@id/bottom_nav" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" android:layout_width="match_parent" android:layout_height="@dimen/dp72" android:background="@color/colorWhite" app:elevation="@dimen/dp15" app:itemTextAppearanceActive="@style/MyBottomNavigationView.TextAppearance" app:itemTextAppearanceInactive="@style/MyBottomNavigationView.TextAppearance" app:itemIconTint="@color/bottom_nav_icon_color_selector" app:itemTextColor="@color/bottom_nav_text_color" android:theme="@style/BottomNavigationViewStyle" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:menu="@menu/bottom_nav" /> </androidx.constraintlayout.widget.ConstraintLayout>
BottomNavigationView样式代码
<style name="BottomNavigationViewStyle" parent="MainThemeV2"> <item name="colorSecondaryContainer">@null</item> <item name="colorError">@color/v2Secondary</item> <item name="labelVisibilityMode">labeled</item> </style>
问题原因
fitsSystemWindows的作用:当View设置该属性为true时,会自动添加padding避开系统窗口(状态栏、虚拟导航栏)。根布局设置后,会为自身添加底部padding以避开虚拟导航栏。- BottomNavigationView的默认行为:作为Material Design组件,它内部默认会处理
WindowInsets,自动添加底部内边距适配虚拟导航栏。 - 双重适配冲突:两者叠加后,BottomNavigationView底部出现双倍内边距,表现为导航栏上移、底部空白;若根布局设为
false,则根布局不处理状态栏适配,导致Toolbar被状态栏遮挡。
解决方案
方案一:保留根布局适配,禁用BottomNavigationView的自动内边距
给BottomNavigationView添加android:fitsSystemWindows="false",阻止它自行处理系统窗口内边距,依赖根布局的padding完成适配:
<com.google.android.material.bottomnavigation.BottomNavigationView ... android:fitsSystemWindows="false" />
方案二:根布局禁用适配,单独处理Toolbar的状态栏padding
- 根布局设置
android:fitsSystemWindows="false" - 给Toolbar添加状态栏高度的顶部padding,避免被遮挡:
<androidx.appcompat.widget.Toolbar ... android:paddingTop="?attr/statusBarHeight" />
此时BottomNavigationView会自动处理底部虚拟导航栏的适配,不会出现多余内边距。
方案三:手动处理WindowInsets(灵活可控)
根布局设置android:fitsSystemWindows="false",在Activity中通过代码手动控制各View的内边距:
import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat ViewCompat.setOnApplyWindowInsetsListener(parent) { _, insets -> val statusBarInsets = insets.getInsets(WindowInsetsCompat.Type.statusBars()) val navigationBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars()) // 适配Toolbar状态栏 toolbar.setPadding(toolbar.paddingLeft, statusBarInsets.top, toolbar.paddingRight, toolbar.paddingBottom) // 让Fragment内容避开底部导航栏 nav_host_fragment.setPadding( nav_host_fragment.paddingLeft, 0, nav_host_fragment.paddingRight, navigationBarInsets.bottom ) // BottomNavigationView紧贴底部,无需额外padding bottom_nav.setPadding(bottom_nav.paddingLeft, bottom_nav.paddingTop, bottom_nav.paddingRight, 0) insets }
内容的提问来源于stack exchange,提问作者hushed_voice
相关产品推荐
相关产品推荐

