防止覆盖导航栏的BottomSheetDialogFragment

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

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 } } 

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

 LogoutBottomSheetFragment().show(supportFragmentManager, "logout") 

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

我正在使用的应用主题:

     </style  true false   @color/colorPrimary  @android:color/white  @color/charcoal_grey @color/charcoal_grey @color/charcoal_grey @color/charcoal_grey @color/charcoal_grey @color/charcoal_grey @color/white  

我也尝试覆盖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) } 

    BottomSheetDialogFragment扩展了DialogFragment 。 在BottomSheetDialog里面,它在onCreateDialog创建一个Dialog

     public class BottomSheetDialogFragment extends AppCompatDialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new BottomSheetDialog(getContext(), getTheme()); } } 

    昏暗层是对话框的属性,适用于整个窗口。 然后它只会覆盖状态栏。 如果您需要没有底部按钮的昏暗图层,则必须通过在布局内显示图层并相应更改状态栏颜色来手动执行。

    如下所示,为dialogfragment应用主题

     class LogoutBottomSheetFragment : BottomSheetDialogFragment() { init { setStyle(DialogFragment.STYLE_NORMAL,R.style.dialog); } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.view_image_source_chooser, container, false) return view } } 

    风格如同

       

    来自j2esu的回答非常好。 但是,如果您坚持使用“完全白色”导航栏,则必须省略其中的一部分。

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

    你需要:

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

    将此代码放在BottomSheetDialogFragment子项的onStart上。 如果您使用的是设计库而不是材料库,请使用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); } } 

    结果可能如下所示:

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

    我有同样的问题 ,我终于find了一个解决方案,它不是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); } } 

    方法“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; } 

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

    之前和之后

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

    您可以将此作为示例

    我有同样的问题。 在查看来源后,我find了一个解决方法(有点hacky,但我没有find替代方案)。

     public class YourDialog extends BottomSheetDialogFragment { //your code @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new FitSystemWindowsBottomSheetDialog(getContext()); } } public class FitSystemWindowsBottomSheetDialog extends BottomSheetDialog { public FitSystemWindowsBottomSheetDialog(Context context) { super(context); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getWindow() != null && Build.VERSION.SDK_INT >= 21) { findViewById(android.support.design.R.id.coordinator).setFitsSystemWindows(false); findViewById(android.support.design.R.id.container).setFitsSystemWindows(false); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); } } } 

    最后,不要忘记在对话框布局的根目录中添加android:fitsSystemWindows =“true”

    希望能帮助到你。