简体   繁体   中英

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

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

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.

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;

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_COLLAPSED it will animate your BottomSheet until 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
[ 自定义BottomSheetBehavior ]

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

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

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

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

Get a reference to the sheet behavior:

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

Turn fitToContents off and set expandedOffset to the desired value, for example:

sheet.isFitToContents = false
sheet.expandedOffset = 100

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM