阻止BottomSheetDialogFragment覆盖导航栏

ofe*_*iko 24 android navigationbar android-layout android-view bottom-sheet

我正在使用非常天真的代码来显示底部对话框片段:

class LogoutBottomSheetFragment : BottomSheetDialogFragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.view_image_source_chooser, container, false)
        return view
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我调用此对话框的方式:

LogoutBottomSheetFragment().show(supportFragmentManager, "logout")
Run Code Online (Sandbox Code Playgroud)

但是我在下面的图片中看到了这个可怕的东西.如何将导航栏保持为白色(背面/主页软件按钮所在的底栏)?

我正在使用的应用主题:

 <!-- Base application theme. -->
<style name="BaseAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
</style

<style name="AppTheme" parent="BaseAppTheme">
    <item name="android:windowNoTitle">true</item>
    <item name="windowActionBar">false</item>

    <!-- Main theme colors -->
    <!--   your app branding color for the app bar -->
    <item name="android:colorPrimary">@color/colorPrimary</item>
    <!--   darker variant for the status bar and contextual app bars -->
    <item name="android:colorPrimaryDark">@android:color/white</item>
    <!--   theme UI controls like checkboxes and text fields -->
    <item name="android:colorAccent">@color/charcoal_grey</item>

    <item name="colorControlNormal">@color/charcoal_grey</item>
    <item name="colorControlActivated">@color/charcoal_grey</item>
    <item name="colorControlHighlight">@color/charcoal_grey</item>

    <item name="android:textColorPrimary">@color/charcoal_grey</item>
    <item name="android:textColor">@color/charcoal_grey</item>

    <item name="android:windowBackground">@color/white</item>
</style>
Run Code Online (Sandbox Code Playgroud)

我也尝试覆盖setupDialog而不是onCreateView,但仍然会发生:

    @SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) {
    super.setupDialog(dialog, style)
    val view = View.inflate(context, R.layout. view_image_source_chooser,null)
    dialog.setContentView(view)
}
Run Code Online (Sandbox Code Playgroud)

Yos*_*sef 29

我知道这里已经有很多解决方案,但所有这些对我来说似乎都太多了,所以我在这里找到了这个非常简单的解决方案,归功于Arthur Nagy

只需覆盖 BottomSheetDialogFragment 中的 getTheme 方法:

override fun getTheme(): Int  = R.style.Theme_NoWiredStrapInNavigationBar
Run Code Online (Sandbox Code Playgroud)

在styles.xml中:

<style name="Theme.NoWiredStrapInNavigationBar" parent="@style/Theme.Design.BottomSheetDialog">
    <item name="android:windowIsFloating">false</item>
    <item name="android:navigationBarColor">@color/bottom_sheet_bg</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>
Run Code Online (Sandbox Code Playgroud)

您还可以通过更改资产文件夹中的颜色@color/bottom_sheet_bg来添加对夜间模式的支持values-night

  • `&lt;item name="android:windowIsFloating"&gt;false&lt;/item&gt;` 修复了问题 (4认同)
  • 谢谢兄弟,你拯救了我的一天。 (2认同)

Den*_*ura 22

我遇到了同样的问题,我终于找到了一个非hacky或需要一定数量的代码的解决方案.

此方法使用LayerDrawable替换窗口背景,LayerDrawable由两个元素组成:背景暗淡和导航栏背景.

@RequiresApi(api = Build.VERSION_CODES.M)
private void setWhiteNavigationBar(@NonNull Dialog dialog) {
    Window window = dialog.getWindow();
    if (window != null) {
        DisplayMetrics metrics = new DisplayMetrics();
        window.getWindowManager().getDefaultDisplay().getMetrics(metrics);

        GradientDrawable dimDrawable = new GradientDrawable();
        // ...customize your dim effect here

        GradientDrawable navigationBarDrawable = new GradientDrawable();
        navigationBarDrawable.setShape(GradientDrawable.RECTANGLE);
        navigationBarDrawable.setColor(Color.WHITE);

        Drawable[] layers = {dimDrawable, navigationBarDrawable};

        LayerDrawable windowBackground = new LayerDrawable(layers);
        windowBackground.setLayerInsetTop(1, metrics.heightPixels);

        window.setBackgroundDrawable(windowBackground);
    }
}
Run Code Online (Sandbox Code Playgroud)

方法"setLayerInsetTop"需要API 23,但这很好,因为在Android O(API 26)中引入了暗导航栏图标.

因此,解决方案的最后一部分是从底层的onCreate方法中调用此方法.

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = super.onCreateDialog(savedInstanceState);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
        setWhiteNavigationBar(dialog);
    }

    return dialog;
}
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助,如果您发现此解决方案不起作用的设备或案例,请告诉我.

之前和之后

  • 这是最干净的答案。另外,如果只想使用activity的导航栏颜色,可以直接使用navigationBarDrawable.setColor(activity.getWindow().getNavigationBarColor())。 (4认同)
  • 这非常简单:您必须在App主题中覆盖bottomSheetTheme,而在bottomSheetTheme中覆盖bottomSheetStyle。现在,您可以在bottomSheetStyle中将背景设置为带有矩形和角的可绘制对象。而已。 (2认同)

And*_*mon 9

无需代码!使用材质组件:

<style name="Theme.YourApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    ...
    <item name="bottomSheetDialogTheme">@style/ThemeOverlay.YourApp.BottomSheetDialog</item>
</style>
Run Code Online (Sandbox Code Playgroud)
<style name="Widget.YourApp.BottomSheet" parent="Widget.MaterialComponents.BottomSheet"/>
Run Code Online (Sandbox Code Playgroud)
<style name="ThemeOverlay.YourApp.BottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/Widget.YourApp.BottomSheet</item>
    <item name="android:windowIsFloating">false</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:navigationBarColor">?colorSurface</item>
</style>
Run Code Online (Sandbox Code Playgroud)

  • 根据material.io 上的文档,这似乎是最正确的答案。但是,我似乎无法使其工作......没有任何变化:导航栏颜色和底部工作表小部件的样式都没有变化。有什么提示我可能做错了什么吗?谢谢! (3认同)

fra*_*kee 8

有一种方法可以避免更改 Java/Kotlin 代码,现在这个问题可以在 XML 中完全解决:

<style name="MyTheme" parent="Theme.MaterialComponents">
    <item name="bottomSheetDialogTheme">@style/BottomSheet</item>
</style>

<style name="BottomSheet" parent="Theme.MaterialComponents.Light.BottomSheetDialog">
    <item name="android:windowIsFloating">false</item>
    <item name="android:statusBarColor">@android:color/transparent</item>         
    <item name="android:navigationBarColor">?android:colorBackground</item>
    <item name="android:navigationBarDividerColor">?android:colorBackground</item>
</style>
Run Code Online (Sandbox Code Playgroud)

我也有一个问题,我的主题/样式没有应用于里面的视图BottomSheetDialogFragment,这是我在我的基础中修复它的方法BottomSheetDialogFragment

override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater {
    val inflater = super.onGetLayoutInflater(savedInstanceState)
    val wrappedContext = ContextThemeWrapper(requireContext(), R.style.My_Theme)
    return inflater.cloneInContext(wrappedContext)
}
Run Code Online (Sandbox Code Playgroud)


mro*_*zis 5

来自j2esu的答案效果很好。但是,如果您坚持使用“全白”导航栏,则必须忽略其中的一部分。

请注意,此解决方案适用于Android O(API 26),因为此版本中引入了深色导航栏图标。在较旧的版本上,您会在白色背景上得到白色图标。

你需要:

  1. 添加android:fitsSystemWindows="true"到对话框布局的根目录。
  2. 修改Window你的Dialog正确。

将此代码放入onStart您的的孩子BottomSheetDialogFragment。如果您使用设计库而不是材料库,请使用android.support.design.R.id.container

@Override
public void onStart() {
    super.onStart();
    if (getDialog() != null && getDialog().getWindow() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        Window window = getDialog().getWindow();
        window.findViewById(com.google.android.material.R.id.container).setFitsSystemWindows(false);
        // dark navigation bar icons
        View decorView = window.getDecorView();
        decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果可能如下所示:

对话框中Android P上的白色导航栏


Mic*_*ł K 5

在中BottomSheetDialogFragment,唯一需要做的就是将基础容器设置CoordinatorLayout fitSystemWindowsfalse

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    (view!!.parent.parent.parent as View).fitsSystemWindows = false
}
Run Code Online (Sandbox Code Playgroud)
  • view 是你的布局
  • view.parent 是包含您的视图的FrameLayout
  • view.parent.parent 是个 CoordinatorLayout
  • view.parent.parent.parent是默认情况下CoordinatorLayout为其fitsSystemWindow设置的容器true

这样可以确保将整体BottomSheetDialogFragment绘制在导航栏下方。然后,您可以相应fitsSystemWindows地将设置为自己的容器。

从其他答案中您尤其不需要的是:

  • hacky findViewById和系统ID的引用,系统ID可能会发生变化,
  • 引用getWindow()getDialog()
  • 在导航栏位置未设置可绘制对象。

此解决方案与BottomSheetDialogFragment创建配合使用onCreateView,我没有检查onCreateDialog


Far*_*ahi -4

不要使用BottomSheetDialogFragment。我更喜欢通过将布局包装在协调器布局中并将 BottomSheetBehaiviour 附加到该布局来添加底部工作表

你可以按照这个例子