BooleanCheese
BooleanCheese

Reputation: 635

How to create an android Bottom sheet that fits the size of the sheet with view always aligned to bottom?

I had a bit of trouble figuring out how to word this one when researching so I've made a quick mockup of what I'm trying to achieve below. my app has a persistent bottom sheet and I would like the contents of the sheet to be resized based on whether the sheet is expanded or half expanded.

My sheet consists of a recycler view and a view at the bottom with some buttons. Currently, the contents of the sheet are always sized as though the sheet is full expanded. This means that the buttons are not displayed unless the sheet is fully expanded and much of the recycler view is also hidden behind the cropped-off sheet. What I want to happen is for the buttons to always be displayed at the bottom of the sheet, even when said sheet is half expanded, and for the recyclerview to fill whatever space is left. Is this possible in a persistent bottom sheet and if now, what means should I use to achieve this? And help would be greatly appreciated.

Mockup

Upvotes: 4

Views: 4947

Answers (1)

Zain
Zain

Reputation: 40878

You can make the buttons layout to always be displayed at the bottom of the sheet by setting its y coordinate by tracking the bottom sheet sliding using addBottomSheetCallback callbacks:

val bottomSheet = findViewById<ConstraintLayout>(R.id.bottom_sheet)
val bottomLayout = findViewById<LinearLayout>(R.id.button_layout)

// initial setting the y coordinates of the bottom layout
bottomSheet.post {
    val bottomSheetVisibleHeight = bottomSheet.height - bottomSheet.top
    bottomLayout.y =
        (bottomSheetVisibleHeight - bottomLayout.height).toFloat()
}

BottomSheetBehavior.from(bottomSheet).apply {

    addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
        override fun onSlide(bottomSheet: View, slideOffset: Float) {
        
            // set the y coordinates of the bottom layout on bottom sheet slide
            val bottomSheetVisibleHeight = bottomSheet.height - bottomSheet.top
            bottomLayout.y =
                (bottomSheetVisibleHeight - bottomLayout.height).toFloat()
        }

        override fun onStateChanged(bottomSheet: View, newState: Int) {
        }
    })
}

Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">

    <!--    Main Layout -->
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/bottom_sheet"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            app:behavior_hideable="false"
            app:layout_behavior="@string/bottom_sheet_behavior">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerview"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:background="#CFE2F3"
                app:layout_constraintBottom_toTopOf="@+id/button_layout"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <LinearLayout
                android:id="@+id/button_layout"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:background="#FF03DAC5"
                android:orientation="horizontal"
                app:layout_constraintBottom_toBottomOf="parent">

                <Button
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginStart="8dp"
                    android:layout_marginEnd="40dp"
                    android:layout_weight="1"
                    android:text="cancel" />

                <Button
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="8dp"
                    android:layout_weight="1"
                    android:text="ok" />

            </LinearLayout>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Upvotes: 4

Related Questions