How to set Bottom Sheet peek height to show only certain parts initially?

15,413

Solution 1

I would solve this by using a ViewTreeObserver.OnGlobalLayoutListener to wait for your bottom sheet to be laid out, and then calling BottomSheetBehavior.setPeekHeight() with the y-coordinate of the first view you don't want to see.

private BottomSheetBehavior<View> behavior;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    View bottomSheet = findViewById(R.id.bottomSheet);
    behavior = BottomSheetBehavior.from(bottomSheet);

    final LinearLayout inner = findViewById(R.id.inner);
    inner.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            inner.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            View hidden = inner.getChildAt(2);
            behavior.setPeekHeight(hidden.getTop());
        }
    });
}

In this case, my bottom sheet is a NestedScrollView holding a LinearLayout that holds many TextViews. By setting the peek height to be the top of the third TextView (obtained by getChildAt(2)), my bottom sheet winds up showing exactly two TextViews while collapsed.

enter image description here enter image description here

Solution 2

Customized @Ben P.'s answer to target a view id as a reference of the peekHeight and made a function:

/**
 * Gets the bottom part of the target view and sets it as the peek height of the specified @{BottomSheetBehavior}
 *
 * @param layout - layout of the bottom sheet.
 * @param targetViewId - id of the target view. Must be a view inside the 'layout' param.
 * @param behavior - bottom sheet behavior recipient.
 */
private fun <T : ViewGroup> getViewBottomHeight(layout: ViewGroup,
                                                targetViewId: Int,
                                                behavior: BottomSheetBehavior<T>) {
    layout.apply {
        viewTreeObserver.addOnGlobalLayoutListener(
                object : ViewTreeObserver.OnGlobalLayoutListener {
                    override fun onGlobalLayout() {
                        viewTreeObserver.removeOnGlobalLayoutListener(this)
                        behavior.peekHeight = findViewById<View>(targetViewId).bottom
                    }
                })
    }
}

In our use case, we needed to target the bottom part of the view, so we set it that way. It can be adjusted depending on the use-case.

Share:
15,413
Damn Vegetables
Author by

Damn Vegetables

I don't want any damn vegetables.

Updated on June 04, 2022

Comments

  • Damn Vegetables
    Damn Vegetables about 2 years

    Let's say that my Bottom Sheet has lines of widgets like the following. If I want to show only the first two lines (i.e., the first two LinearLayouts) initially, but not the rest of the widgets below. I do not want those to be seen initially. How can I set the correct peek height? Hard-coding app:behavior_peekHeight probably would not work, so I would need to set it programatically, but how to calculate the height?

    Or is there a more recommended way to get the same result? I mean, if I test Google Maps, long pressing a location first shows only the title part as the bottom sheet, but when I try to scroll up the bottom sheet, it feels as if the title part (which might not have been a real bottom sheet) is replaced by a real bottom sheet that contains all the elements. If my explanation is not enough, please try Google Maps yourself.

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/bottom_sheet"
        app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <TextView/>
                <android.support.v7.widget.AppCompatSpinner/>
            </LinearLayout>
            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <TextView/>
                <TextView/>
            </LinearLayout>
            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <TextView/>
                <TextView/>
            </LinearLayout>
            <android.support.v7.widget.RecyclerView/>
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
    
  • ShresthaGanesh
    ShresthaGanesh over 4 years
    can i get the layout file for this code and if possible the code too.. I am trying to set the peekheight same as the location where i have dragged the bottomsheet. But i couldnot find the value of currently dragged location.