BottomSheetDialogFragment - How to set expanded height (or min top offset)

AndroidAndroid Support-LibraryAndroiddesignsupportBottom Sheet

Android Problem Overview


I create a BottomSheetDialogFragment and I want to adjust it's maximum expanded height. How can I do that? I can retrieve the BottomSheetBehaviour but all I can find is a setter for the peek height but nothing for the expanded height.

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?

    }
}

EDIT

Why do I need that? Because I show a BottomSheet Dialog in a full screen activity and it looks bad if the BottomSheet leaves a space on top...

Android Solutions


Solution 1 - Android

The height is being wrapped because the inflated view is added to the FrameLayout which has layout_height=wrap_content. See FrameLayout (R.id.design_bottom_sheet) at https://github.com/dandar3/android-support-design/blob/master/res/layout/design_bottom_sheet_dialog.xml.

The class below makes the bottom sheet full screen, background transparent, and fully expanded to the top.

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)

        });
    }

}

--- EDIT Aug 30, 2018 --- I realized a year later that the background was colored on the wrong view. This dragged the background along with the content while a user was dragging the dialog. I fixed it so that the parent view of the bottom sheet is colored.

Solution 2 - Android

I found a much simpler answer; in your example where you obtain the FrameLayout for the bottom sheet using this code

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

you can then set the height on the layout params for that View to whatever height you want to set the expanded height to.

bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;

Solution 3 - Android

BIG UPDATE Avoiding duplicated code I'm giving a link to the full answer in where you can find all the explanations about how to get full behavior like Google Maps.


> I want to adjust its maximum expanded height. How can I do that?

Both BottomSheet and BottomSheetDialogFragment use a BottomSheetBehavior that you can found in Support Library 23.x

That Java class has 2 different uses for mMinOffset, one of them is used to define the area of the parent it will use to draw his content (maybe a NestedScrollView). And the other use is for defining the expanded anchor point, I mean, if you slide it up to form STATE_COLLAPSEDit will animate your BottomSheetuntil he reached this anchor point BUT if you can still keep sliding up to cover all parent height (CoordiantorLayout Height).

If you took a look at BottomSheetDialog you will see this method:

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



No idea which one of those 2 behaviors you want but if you need the second one follow those steps:

  1. Create a Java class and extend it from CoordinatorLayout.Behavior<V>

  2. Copy paste code from the default BottomSheetBehavior file to your new one.

  3. Modify the method clampViewPositionVertical with the following code:

    @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. Add a new state

    public static final int STATE_ANCHOR_POINT = X;
    
  5. Modify the next methods: onLayoutChild, onStopNestedScroll, BottomSheetBehavior<V> from(V view) and setState (optional)

And here is how it looks like
[CustomBottomSheetBehavior]

Solution 4 - Android

Its works for me. Add code on BottomSheetDialogFragment's onViewCreated() methode

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
}

Don't forget to remove viewTreeObserver.

override fun onDestroyView() {
    dialogView?.viewTreeObserver?.addOnGlobalLayoutListener(null)
    super.onDestroyView()
}

Solution 5 - Android

Get reference to sheet behavior,

private val behavior by lazy { (dialog as BottomSheetDialog).behavior }

turn fitToContents off and set expandedOffset to desired pixels.

behavior.isFitToContents = false
behavior.expandedOffset = 100

Solution 6 - Android

Kotlin

In my case I need to define a fixed height and I did the following:

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

this way you also have access to any property of the BottomSheetBehavior such as halfExpandedRatio

Solution 7 - Android

I would advise against using ids to find views. In the BottomSheetDialogFragment the dialog is a BottomSheetDialog which exposes the behavior for the bottom sheet. You can use that to set the peek height.

(dialog as BottomSheetDialog).behavior.peekHeight = ...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionprom85View Question on Stackoverflow
Solution 1 - AndroidRubin YooView Answer on Stackoverflow
Solution 2 - AndroidJason SznolView Answer on Stackoverflow
Solution 3 - AndroidMiguelHincapieCView Answer on Stackoverflow
Solution 4 - AndroidMubarakView Answer on Stackoverflow
Solution 5 - AndroidapsommerView Answer on Stackoverflow
Solution 6 - AndroidJuanes30View Answer on Stackoverflow
Solution 7 - AndroidXidView Answer on Stackoverflow