androidandroid-recyclerviewandroid-constraintlayoutandroid-nestedscrollviewnestedrecyclerview

Align two views in opposites sides (one at the top and one at the bottom) and be able to push the bottom view when the top view grows?


I basically have an EditText aligned at the top of the view and there's a RecyclerView on the bottom of the view that can also grow (with the newest item on the bottom) That's easily doable with a constraint layout but my problem is that when the EditText grows it should start pushing down the list. But the list was initially aligned at the bottom of the parent. (and everything should be scrollable) I hope this image makes things more clear

enter image description here


Solution

  • The trick here is to avoid forming a vertical chain (so that the EditText at the top always stays in place) and also to leverage the app:layout_constrainedHeight attribute on the RecyclerView in order to make it shrink when the EditText grows.

    <?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">
    
        <EditText
            android:id="@+id/text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constrainedHeight="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/text"
            app:layout_constraintVertical_bias="1"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    The combination of android:layout_height="wrap_content" and app:layout_constrainedHeight="true", along with both top and bottom constraints, means that the RecyclerView will always be only as tall as its items or the available space below the EditText, whichever is smaller.

    The app:layout_constraintVertical_bias="1" attribute ensures that, when the list doesn't fill the screen, it sits at the bottom.