'How to make RecyclerView be always up to BottomSheet and under AppBarLayout?

I have a layout with AppBarLayout which height is set dynamically by adding some margins if the device has the notch, BottomSheetLayout and a RecyclerView.

The goal:

I need to make the RecyclerView fit between the AppBar and the top of BottomSheetLayout when it's expanded or collapsed, so the items from RecyclerView never must go under the BottomSheet or AppBarLayout.

I was playing with onSlide method to archieve so:

bottomsheet.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        if (newState == BottomSheetBehavior.STATE_EXPANDED) {
            recyclerPiatti.scrollToPosition(listPiatti.size() - 1);
        }
    }

    @Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        findViewById(R.id.arrowIcon).setRotation(slideOffset * 180);
        int margin = bottomSheet.getHeight();
        if (!Float.isNaN(slideOffset)) {
            margin *= (1 - Math.abs(slideOffset));
            setRecyclerViewHeight(margin);
        }
    }
});

And tried to set initial margins of the RecyclerView in onAttachedToWindow (where i set dynamically the height of appBar)

    bottomsheet.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                recyclerPiatti.scrollToPosition(listPiatti.size() - 1);
            }
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            findViewById(R.id.arrowIcon).setRotation(slideOffset * 180);
            int margin = bottomSheet.getHeight();
            if (!Float.isNaN(slideOffset)) {
                margin *= (1 - Math.abs(slideOffset));
                setRecyclerViewHeight(margin);
            }
        }
    });

private void setRecyclerViewHeight(int marginBottom) {
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) recyclerPiatti.getLayoutParams();
    params.setMargins(0, findViewById(R.id.appBar).getHeight(), 0, marginBottom);
    recyclerPiatti.setLayoutParams(params);
    recyclerPiatti.requestLayout();
}

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    Utils.adjustToolbarForNotch(this, findViewById(R.id.appBar));
    setRecyclerViewHeight(findViewById(R.id.bottomSheet).getHeight());
}

The layout:

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/menuToolbar"
            style="@style/Widget.MaterialComponents.Toolbar.Primary"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:navigationIcon="@drawable/ic_baseline_close_white"
            app:title="Menù componibile" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerPiatti"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:clipToPadding="false"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:listitem="@layout/layout_menu_componibile" />


    <LinearLayout
        android:id="@+id/bottomSheet"
        android:background="@drawable/background_bottomsheet"
        android:layout_width="match_parent"
        android:layout_height="450dp"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
        app:behavior_hideable="false"
        android:elevation="5dp"
        app:behavior_peekHeight="200dp"
        android:orientation="vertical">

        <RelativeLayout
            android:layout_width="match_parent"
            android:gravity="center_horizontal"
            android:layout_height="60dp">

            <View
                android:id="@+id/expandButton"
                android:layout_width="75dp"
                android:layout_height="40dp"
                android:background="@drawable/bottom_border_radius"
                android:clickable="true"
                android:contentDescription="@string/bottom_sheet_close_button"
                android:elevation="8dp"
                android:focusable="true"
                android:padding="10dp" />

            <ImageView
                android:id="@+id/arrowIcon"
                android:layout_width="75dp"
                android:layout_height="40dp"
                android:padding="8dp"
                android:contentDescription="@string/bottom_sheet_close_button"
                android:src="@drawable/ic_keyboard_arrow_up" />

        </RelativeLayout>

    ...

    </LinearLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>

But instead it's initial state is not even set and when the BottomSheet is expanded or collapsed the RecyclerView just get resized in a weird way..

The BottomSheet initial state in onCreate is set to EXPANDED.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source