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

101,948

Solution 1

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

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

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

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

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
Share:
101,948
prom85
Author by

prom85

Updated on July 05, 2022

Comments

  • prom85
    prom85 almost 2 years

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

    • eRaisedToX
      eRaisedToX about 7 years
      I am interested in knowing that how can I set max height for `modal bottom sheet``. I need my modal bottom sheet to go till half screen only and never till top even after dragging...Any clues?
    • Pratik Butani
      Pratik Butani over 5 years
      @abat Hope it will helps : stackoverflow.com/a/53791225/1318946
    • Pratik Butani
      Pratik Butani over 5 years
      @eRaisedToX You can also try : stackoverflow.com/a/53791225/1318946
  • hmac
    hmac almost 4 years
    with androidX use: dialog?.findViewById<View>( com.google.android.material.R.id.design_bottom_sheet )
  • hmac
    hmac almost 4 years
    with androidX use: dialog?.findViewById<View>( com.google.android.material.R.id.design_bottom_sheet )
  • hmac
    hmac almost 4 years
    can someone explain why the find bottom sheet view doesn't seem to work from onCreateDialog or onViewCreated?
  • Javad B
    Javad B almost 4 years
    This is a great solution! Thanks for this complete answer Miguel
  • Owen Chen
    Owen Chen about 3 years
    Using addOnGlobalLayoutListener will cause screen flash, the main logic can be legal in onViewCreated
  • akashzincle
    akashzincle about 3 years
    one thing I noticed, this works, only when the parent layout of our bottomsheet is RelativeLayout
  • akashzincle
    akashzincle about 3 years
    One thing I noticed, decorview is considering Navigation view height too, so any view aligned bottom of parent is cutting at the bottom, after replacing activity?.window?.decorView?.measuredHeight with height fetched in pixels using displaymetrics, worked for me
  • Shailendra Madda
    Shailendra Madda about 2 years
    View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet); bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; This is what I am looking for