Search code examples
androidandroid-layoutandroid-constraintlayoutandroid-relativelayout

ConstraintLayout Does Not Work Properly in a Bottom Sheet View


Issue

The ConstraintLayout does not work as expected when used in a Bottom sheet. In this instance a ConstraintLayout contains 2 images comprising the handle and 1 view for the content in the Bottom Sheet. The content view is supposed to be placed below the handle images which is not happening.

Implementation

<androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/bottomSheet"
            android:layout_width="match_parent"
            android:layout_height="350dp"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

            <ImageView
                android:id="@+id/bottom_handle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:background="@drawable/ic_bottom_sheet_handle"
                android:contentDescription="@string/saved_bottomsheet_handle_content_description"
                android:elevation="16dp"
                android:src="@drawable/ic_save_planet_dark_48dp"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="@dimen/bottom_sheet_elevation_height"
                android:background="@color/bottom_sheet_handle_elevation"
                android:contentDescription="@string/saved_bottomsheet_handle_content_description"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toBottomOf="@id/bottom_handle" />

            <FrameLayout
                android:id="@+id/savedContentContainer"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/white"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toBottomOf="@id/bottom_handle" />

        </androidx.constraintlayout.widget.ConstraintLayout>

Result

The Actionbar from the content view is floating behind the handle views.

enter image description here

Expected Result

The handle sits above the content view and Action Bar.

enter image description here

Possible Solution

As much as I'd rather use the ConstraintLayout over RelativeLayout, RelativeLayout works here.

<RelativeLayout
            android:id="@+id/bottomSheet"
            android:layout_width="match_parent"
            android:layout_height="350dp"
            android:elevation="16dp"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

            <ImageView
                android:id="@+id/bottom_handle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:background="@drawable/ic_bottom_sheet_handle"
                android:contentDescription="@string/saved_bottomsheet_handle_content_description"
                android:elevation="16dp"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:src="@drawable/ic_save_planet_dark_48dp" />

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="@dimen/bottom_sheet_elevation_height"
                android:background="@color/bottom_sheet_handle_elevation"
                android:contentDescription="@string/saved_bottomsheet_handle_content_description"
                android:layout_alignBottom="@id/bottom_handle"/>

            <FrameLayout
                android:layout_below="@id/bottom_handle"
                android:id="@+id/savedContentContainer"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/white" />

        </RelativeLayout>

Solution

  • Using match_parent for children of ConstraintLayout is not recommended as stated in the documentation:

    Important: MATCH_PARENT is not recommended for widgets contained in a ConstraintLayout. Similar behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom constraints being set to "parent".

    In your case setting height to match_parent for the FrameLayout causes it to take the parent's height regardless of the constraints.

    Instead of using match_parent you should add the bottom constraint for your FrameLayout and use 0dp to match_constraint for height:

    <FrameLayout
        android:id="@+id/savedContentContainer"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/bottom_handle" />