steventnorris
steventnorris

Reputation: 5896

RecyclerView pushes its below button out of the screen in ConstraintLayout

I am attempting to set up a layout with an "X" button pinned to the top of the screen, and then two elements centered in the view. One a recycler view and then, pinned below the recycler view, a button for form submission. The layout I currently have worked until the recycler view outgrows its bounds. Then the submission button is pushed below the bounds of the view and the recycler view does not stay within the layout. How can I center the two recycler and button views but not have the button go past view bounds if the recycler view grows large?

View With Small Recycler View Appears As (it should be centered. my example is slightly off.)

enter image description here

How View Should Appear with Larger Recycler View (the recycler view's content is too large to fit so it scrolls)

enter image description here

How View Actually Appears with Larger Recycler View (the recycler view does scroll, but now it pushes the button off the bottom of the view, which appears as the button being cut off)

enter image description here

Relevant Code Block for XML Layout

<LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="0.45"
        android:orientation="vertical"
        android:background="@color/backgroundLightSecondary"
        android:padding="20dp" >

        <Button
            android:id="@+id/bt_close"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_gravity="end"
            android:background="@drawable/ic_close"
            android:textColor="@color/textLightPrimary"  />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:orientation="vertical"
            android:layout_weight="1"
            android:gravity="center_vertical">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical">

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv_item_options"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

            </androidx.constraintlayout.widget.ConstraintLayout>

            <Button
                android:id="@+id/bt_order"
                android:layout_width="150dp"
                android:layout_height="50dp"
                android:layout_weight="0"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                android:background="@drawable/bt_rounded_corner"
                android:fontFamily="@font/microbrew_two"
                android:padding="3dp"
                android:text="@string/btn_add_to_order"
                android:textColor="@color/backgroundLightSecondary"
                android:textSize="20sp" />

        </LinearLayout>

    </LinearLayout>

Upvotes: 5

Views: 3465

Answers (3)

aminography
aminography

Reputation: 22832

In such cases, the best way is to use a ConstraintLayout as the container. As you mentioned in the question, you want to lay the RecyclerView at the center. So, it leads to binding its top and bottom to the buttons.

On the other hand, if we make a chain between the RecyclerView and submitButton with a vertical chain style of packed, the submitButton would stick to the bottom of RecyclerView (which height is wrap_content to be able to grow) and moves with its bottom until it reaches the bottom of the screen (because of app:layout_constraintBottom_toBottomOf="parent").

The key point is to set app:layout_constrainedHeight="true" for the RecyclerView leading to not overlap with the two buttons.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp" >

    <androidx.appcompat.widget.AppCompatImageButton
        android:id="@+id/closeImageButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_close_24"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@id/submitButton"
        app:layout_constraintTop_toBottomOf="@id/closeImageButton"
        app:layout_constraintVertical_chainStyle="packed" />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/submitButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Submit"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/recyclerView" />

</androidx.constraintlayout.widget.ConstraintLayout>

Visual Result:

Upvotes: 18

Ensar Bayhan
Ensar Bayhan

Reputation: 943

You can do everything you want in just one hierarchy by using ConstraintLayout. As an example, I edited your XML code as below;

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

<Button
    android:id="@+id/bt_close"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:background="@drawable/ic_close"
    android:textColor="@android:color/white"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_item_options"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginTop="30dp"
    android:layout_marginBottom="10dp"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    app:layout_constraintBottom_toTopOf="@+id/bt_order"
    app:layout_constraintTop_toBottomOf="@+id/bt_close" />

<Button
    android:id="@+id/bt_order"
    android:layout_width="150dp"
    android:layout_height="50dp"
    android:background="@android:color/holo_blue_dark"
    android:padding="3dp"
    android:text="Button"
    android:textColor="@android:color/white"
    android:textSize="20sp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/rv_item_options" />
</androidx.constraintlayout.widget.ConstraintLayout>

Upvotes: 0

Sahil Goyal
Sahil Goyal

Reputation: 425

As I understand You want a button on top followed by recyclerview and than a Submit button in the end.And if size of recyclerview grows Submit button should not change its place.

Try this I make a rough layout

<LinearLayout  //This is root layout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

Output of code looks like this

enter image description here

Upvotes: 0

Related Questions