it-swarm.com.ru

Запретить 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")

Но я вижу это ужасно на картинке ниже. Как я могу держать панель навигации белой (нижняя панель, где находятся кнопки назад/домой)?

Тема приложения, которую я использую:

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

Я также попытался переопределить 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)
}
16
oferiko

У меня было то же самое проблема , и я наконец нашел решение, которое не является хакерским или требует большого количества кода.

Этот метод заменил фон окна на 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;
}

Я надеюсь, что это поможет, и, пожалуйста, дайте мне знать, если вы найдете устройство или случай, в котором это решение не работает.

before and after

5
Denis Schura

В BottomSheetDialogFragment единственное, что нужно сделать, это установить контейнер базового CoordinatorLayoutfitSystemWindows в false.

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    (view!!.parent.parent.parent as View).fitsSystemWindows = false
}
  • view это ваш макет
  • view.parent - это FrameLayout, содержащий ваше представление
  • view.parent.parent является CoordinatorLayout
  • view.parent.parent.parent - это контейнер для CoordinatorLayout, для которого fitsSystemWindow по умолчанию имеет значение true.

Это гарантирует, что вся BottomSheetDialogFragment будет нарисована под панелью навигации. Затем вы можете установить fitsSystemWindows для своих собственных контейнеров соответственно.

Что вам не нужно из других ответов, в частности:

  • хакерский findViewById со ссылкой на системные идентификаторы, которые могут быть изменены,
  • ссылка на getWindow() или getDialog(),
  • на панели навигации не должно быть никаких рисунков.

Это решение работает с BottomSheetDialogFragment, созданным с onCreateView, я не проверял onCreateDialog.

1
Michał K

Ответ от 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);
    }
}

Результат может выглядеть так:

 White navigation bar on Android P in dialog

1
mroczis

BottomSheetDialogFragment extends DialogFragment. Внутри BottomSheetDialog он создает диалог внутри onCreateDialog 

public class BottomSheetDialogFragment extends AppCompatDialogFragment {

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

}

Слой dim - это свойство диалога, которое применяется ко всему окну. Только тогда он будет покрывать строку состояния. Если вам нужен тусклый слой без нижних кнопок, то вам нужно сделать это вручную, показав слой внутри макета и изменив соответствующим образом цвет строки состояния.

Примените тему для 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
    }


}

Со стилями как 

 <style name="dialog" parent="Base.Theme.AppCompat.Dialog">
        <item name="Android:windowBackground">@Android:color/transparent</item>
        <item name="Android:backgroundDimEnabled">false</item>
</style>
0
Sangeet Suresh