BottomSheetDialogFragment — как установить расширенную высоту (или минимальное верхнее смещение)

Я создаю BottomSheetDialogFragment и хочу настроить его максимальную расширенную высоту. Как я могу это сделать? Я могу получить BottomSheetBehaviour, но все, что я могу найти, это установка для высоты просмотра, но ничего для расширенной высоты.

public class DialogMediaDetails extends BottomSheetDialogFragment
{
    @Override
    public void setupDialog(Dialog dialog, int style)
    {
        super.setupDialog(dialog, style);
        View view = View.inflate(getContext(), R.layout.dialog_media_details, null);
        dialog.setContentView(view);

        ...

        View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);
        BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setPeekHeight(...);
        // how to set maximum expanded height???? Or a minimum top offset?

    }
}

ИЗМЕНИТЬ

Зачем мне это нужно? Потому что я показываю диалоговое окно BottomSheet в полноэкранном режиме, и это выглядит плохо, если BottomSheet оставляет пробел сверху...


person prom85    schedule 16.03.2016    source источник
comment
Мне интересно узнать, как установить max height для `модального нижнего листа``. Мне нужно, чтобы мой модальный нижний лист поднимался только до половины экрана и никогда не поднимался вверх даже после перетаскивания... Есть подсказки?   -  person eRaisedToX    schedule 10.04.2017
comment
@abat Надеюсь, это поможет: stackoverflow.com/a/53791225/1318946   -  person Pratik Butani    schedule 15.12.2018
comment
@eRaisedToX Вы также можете попробовать: stackoverflow.com/a/53791225/1318946   -  person Pratik Butani    schedule 15.12.2018


Ответы (6)


Высота переносится, потому что увеличенный вид добавляется в FrameLayout, который имеет layout_height=wrap_content. См. FrameLayout (R.id.design_bottom_sheet) по адресу https://github.com/dandar3/android-support-design/blob/master/res/layout/design_bottom_sheet_dialog.xml.

Приведенный ниже класс делает нижний лист полноэкранным, фон прозрачным и полностью расширяется вверх.

public class FullScreenBottomSheetDialogFragment extends BottomSheetDialogFragment {


    @CallSuper
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ButterKnife.bind(this, view);
    }


    @Override
    public void onStart() {
        super.onStart();
        Dialog dialog = getDialog();

        if (dialog != null) {
            View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);
            bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
        }
        View view = getView();
        view.post(() -> {
            View parent = (View) view.getParent();
            CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) (parent).getLayoutParams();
            CoordinatorLayout.Behavior behavior = params.getBehavior();
            BottomSheetBehavior bottomSheetBehavior = (BottomSheetBehavior) behavior;
            bottomSheetBehavior.setPeekHeight(view.getMeasuredHeight());
            ((View)bottomSheet.getParent()).setBackgroundColor(Color.TRANSPARENT)

        });
    }

}

--- РЕДАКТИРОВАТЬ 30 августа 2018 г. --- Год спустя я понял, что фон был окрашен в неправильном виде. Это перетаскивало фон вместе с содержимым, пока пользователь перетаскивал диалоговое окно. Я исправил это так, чтобы родительский вид нижнего листа был цветным.

person Rubin Yoo    schedule 26.09.2017
comment
с использованием androidX: dialog?.findViewById<View>( com.google.android.material.R.id.design_bottom_sheet ) - person hmac; 02.07.2020
comment
может кто-нибудь объяснить, почему поиск нижнего листа не работает с onCreateDialog или onViewCreated? - person hmac; 02.07.2020

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

View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);

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

bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
person Jason Sznol    schedule 01.06.2016
comment
с использованием androidX: dialog?.findViewById<View>( com.google.android.material.R.id.design_bottom_sheet ) - person hmac; 02.07.2020
comment
я заметил одну вещь, это работает, только когда родительский макет нашего нижнего листа - RelativeLayout - person akashzincle; 10.04.2021

БОЛЬШОЕ ОБНОВЛЕНИЕ Чтобы избежать дублирования кода, я даю ссылку на полный ответ в котором вы можете найти все объяснения о том, как получить полное поведение, такое как Google Maps.


Я хочу настроить его максимальную расширенную высоту. Как я могу это сделать?

И BottomSheet, и BottomSheetDialogFragment используют поведение BottomSheetBehavior, которое можно найти в библиотеке поддержки 23.x

Этот класс Java имеет 2 разных использования для mMinOffset, одно из них используется для определения области родителя, которую он будет использовать для рисования своего содержимого (возможно, NestedScrollView). И другое использование для определения расширенной точки привязки, я имею в виду, если вы сдвинете ее вверх, чтобы сформировать STATE_COLLAPSED, она будет анимировать ваш BottomSheet, пока он не достигнет этой точки привязки, НО если вы все еще можете продолжать скользить вверх, чтобы покрыть всю родительскую высоту (CoordiantorLayout Height).

Если вы взглянете на BottomSheetDialog, вы увидите этот метод:

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
    final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(),
            android.support.design.R.layout.design_bottom_sheet_dialog, null);
    if (layoutResId != 0 && view == null) {
        view = getLayoutInflater().inflate(layoutResId, coordinator, false);
    }
    FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(android.support.design.R.id.design_bottom_sheet);
    BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback);
    if (params == null) {
        bottomSheet.addView(view);
    } else {
        bottomSheet.addView(view, params);
    }
    // We treat the CoordinatorLayout as outside the dialog though it is technically inside
    if (shouldWindowCloseOnTouchOutside()) {
        final View finalView = view;
        coordinator.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (isShowing() &&
                        MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_UP &&
                        !coordinator.isPointInChildBounds(finalView,
                                (int) event.getX(), (int) event.getY())) {
                    cancel();
                    return true;
                }
                return false;
            }
        });
    }
    return coordinator;
}



Понятия не имею, какое из этих двух действий вам нужно, но если вам нужно второе, выполните следующие действия:

  1. Создайте класс Java и расширьте его из CoordinatorLayout.Behavior<V>

  2. Скопируйте и вставьте код из файла BottomSheetBehavior по умолчанию в новый.

  3. Измените метод clampViewPositionVertical следующим кодом:

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
    }
    int constrain(int amount, int low, int high) {
        return amount < low ? low : (amount > high ? high : amount);
    }
    
  4. Добавить новое состояние

    public static final int STATE_ANCHOR_POINT = X;
    
  5. Измените следующие методы: onLayoutChild, onStopNestedScroll, BottomSheetBehavior<V> from(V view) и setState (необязательно)

А вот как это выглядит
[CustomBottomSheetBehavior ]

person MiguelHincapieC    schedule 25.05.2016
comment
Это отличное решение! Спасибо за этот полный ответ Мигель - person Javad Besharati; 16.07.2020

Это работает для меня. Добавьте код в метод BottomSheetDialogFragment onViewCreated().

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {

            view.viewTreeObserver.removeOnGlobalLayoutListener(this)

            val dialog = dialog as BottomSheetDialog
            val bottomSheet = dialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
            val behavior = BottomSheetBehavior.from(bottomSheet!!)
            behavior.state = BottomSheetBehavior.STATE_EXPANDED

            val newHeight = activity?.window?.decorView?.measuredHeight
            val viewGroupLayoutParams = bottomSheet.layoutParams
            viewGroupLayoutParams.height = newHeight ?: 0
            bottomSheet.layoutParams = viewGroupLayoutParams
        }
    })
    dialogView = view
}

Не забудьте удалить viewTreeObserver.

override fun onDestroyView() {
    dialogView?.viewTreeObserver?.addOnGlobalLayoutListener(null)
    super.onDestroyView()
}
person Mubarak    schedule 04.02.2020
comment
Использование addOnGlobalLayoutListener вызовет мерцание экрана, основная логика может быть разрешена в onViewCreated - person Owen Chen; 23.03.2021
comment
Одна вещь, которую я заметил, decorview также учитывает высоту просмотра навигации, поэтому любой вид, выровненный по нижней части родителя, обрезается внизу после замены activity?.window?.decorView?.measuredHeight с высотой, полученной в пикселях с использованием displaymetrics, работал для меня - person akashzincle; 10.04.2021

Котлин

В моем случае мне нужно определить фиксированную высоту, и я сделал следующее:

val bottomSheet: View? = dialog.findViewById(R.id.design_bottom_sheet)
BottomSheetBehavior.from(bottomSheet!!).peekHeight = 250

таким образом, у вас также есть доступ к любому свойству BottomSheetBehavior, например halfExpandedRatio

person Juanes30    schedule 16.10.2019

Я бы посоветовал не использовать идентификаторы для поиска просмотров. В BottomSheetFragmentDialog диалоговое окно BottomSheetDialog показывает поведение нижнего листа. Вы можете использовать это, чтобы установить высоту просмотра.

(dialog as BottomSheetDialog).behavior.peekHeight = ...
person Keyser Söze    schedule 16.06.2021