10

I have a BottomSheetDialogFragment that I want to be able to show on any screen. I've spent the day trying to programmatically change the peek height of the sheet, but nothing seems to be changing it.

Here is my layout, bottom_sheet.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical"
        app:behavior_hideable="true"
        app:behavior_peekHeight="96dp"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <androidx.core.widget.NestedScrollView
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</LinearLayout>

You will notice I have an empty NestedScrollView. This is because I have made my content customizable when I show the bottom sheet on different screens, so I load a custom layout into it through code.

Here is my fragment class:

public class BottomSheetFragment extends BottomSheetDialogFragment {

    private LinearLayout bottomSheet;
    private NestedScrollView contentView;

    public BottomSheetFragment() {

    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.bottom_sheet, container, false);
    }

    @Override
    public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        bottomSheet = view.findViewById(R.id.bottom_sheet);
        contentView = view.findViewById(R.id.content);
    }

    // Set the layout of the NestedScrollView by passing a layout ID
    public void setLayout(int layoutId) {
        if (contentView != null) {
            contentView.removeAllViews();

            View view = getLayoutInflater().inflate(layoutId, contentView, false);

            if (view != null) {
                contentView.addView(view);
            }
        }
    }
}

Then, where I want to show the bottom sheet, I do:

BottomSheetFragment bottomSheetFragment = new BottomSheetFragment();
bottomSheetFragment.show(getSupportFragmentManager(), bottomSheetFragment.getTag());

I want the peek height of the sheet to be 64dp from the top of the screen. How and where would I do this programmatically?

I also found that, even if I change the value of app:behavior_peekHeight="96dp" in the layout to something like 500dp, it still doesn't change anything when I show the sheet.

user9846951
  • 101
  • 1
  • 1
  • 4

5 Answers5

11

There is no view element in your bottom_sheet. Thats why you dont see any change when play around with peekheight.

Set some height to bottom_sheet to view changes. If you set the height (300) for example, you will clearly see the peek height taking effect.

For example,

<LinearLayout
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="@color/colorPrimary"
            android:orientation="vertical"
            android:id="@+id/bottom_sheet"
            app:layout_behavior="@string/bottom_sheet_behavior"
            app:behavior_peekHeight="96dp"
            app:behavior_hideable="true">

            <androidx.core.widget.NestedScrollView
                android:id="@+id/content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>

will Result in

enter image description here

To set peekheight programatically

First you have to put your bottomsheet in coordinate layout like that

<androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="@color/colorPrimary"
            android:orientation="vertical"
            android:id="@+id/bottom_sheet"
            app:layout_behavior="@string/bottom_sheet_behavior"
            app:behavior_peekHeight="96dp"
            app:behavior_hideable="true">

            <androidx.core.widget.NestedScrollView
                android:id="@+id/content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

In your class, you do that.

@Override
    public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        View bottomSheet = view.findViewById(R.id.bottom_sheet);
        BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setPeekHeight(150); 
    }
Usman Zafer
  • 1,261
  • 1
  • 10
  • 15
  • Is there a way to do it without putting it in a Coordinator Layout? I've found that if I use it, it breaks other things. – user9846951 Apr 14 '20 at 15:09
  • Not really. You have to stick to Coordinator Layout. According to Docs, BottomSheetBehavior is an interaction behavior plugin for a child view of CoordinatorLayout – Usman Zafer Apr 14 '20 at 15:17
  • CoordinatorLayout works for this height without programmatically changing height. Thank you – Dhanunjaya Sep 21 '20 at 13:35
3

You can set state STATE_EXPANDED on BottomSheetShow. here's my working code snippet.

@Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

        dialog.setOnShowListener((DialogInterface.OnShowListener) dialog1 -> {
            BottomSheetDialog d = (BottomSheetDialog) dialog1;
            FrameLayout bottomSheet = (FrameLayout) d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
            if (bottomSheet != null)
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
        });

        return dialog;
    }
Amrish Kakadiya
  • 974
  • 1
  • 7
  • 25
2

To set the peek height programmatically, you can:

  1. Override onCreateDialog in your BottomSheetDialogFragment
  2. Cast as BottomSheetDialog
  3. Call setPeekHeight(int, boolean) on the behavior (BottomSheetBehavior)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return super.onCreateDialog(savedInstanceState).apply {
        (this as? BottomSheetDialog)
                ?.behavior
                ?.setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO, true)
    }
}

The BottomSheetBehavior.PEEK_HEIGHT_AUTO sets a 16:9 ratio, and true is whether to animate.

Shazbot
  • 1,444
  • 1
  • 11
  • 21
1

You can set the peek height to your bottom sheet by getting its reference by override OnCreateDialog method inside your BottomSheetFragment

public class BottomSheetFragment extends BottomSheetDialogFragment {

    private LinearLayout bottomSheet;
    private NestedScrollView contentView;

    public BottomSheetFragment() {

    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.bottom_sheet, container, false);
    }

    @Override
    public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        bottomSheet = view.findViewById(R.id.bottom_sheet);
        contentView = view.findViewById(R.id.content);
    }

    /**
     * 
     * Your code to modify the bottom sheet behavior to set peek height which will be used in collapsed state
     * Here I set it to 80 percent of height of my screen
     * You can directly setPeekHeight() to your requirement
     */
    @NonNull @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog bottom_dialog = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) bottom_dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
                assert bottomSheet != null;
                //BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
                DisplayMetrics displayMetrics = requireActivity().getResources().getDisplayMetrics();
                int height = displayMetrics.heightPixels;
                int maxHeight = (int) (height*0.80);
                BottomSheetBehavior.from(bottomSheet).setPeekHeight(maxHeight);
            }
        });

        return dialog;
    }

    // Set the layout of the NestedScrollView by passing a layout ID
    public void setLayout(int layoutId) {
        if (contentView != null) {
            contentView.removeAllViews();

            View view = getLayoutInflater().inflate(layoutId, contentView, false);

            if (view != null) {
                contentView.addView(view);
            }
        }
    }
}
David Buck
  • 3,752
  • 35
  • 31
  • 35
0

You have to overrride onCreateDialog and cast the super.onCreateDialog(savedInstanceState) to BottomSheetDialog that content the methd behavior.setPeekHeight(Int)

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
      behavior.setPeekHeight(resources.displayMetrics.heightPixels / 2)
    }
}
Aziz
  • 41
  • 4