0

I am using constraint layout with a vertical bias to fill view in recycler view. I successfully did that.

<?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:background="@color/white">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recylerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0" />

</androidx.constraintlayout.widget.ConstraintLayout>

My recyclerview items showing me in reverse order because I want to make chat application. So I added reverseLayout and stackFromEnd true. So it look like this.

enter image description here

If my item is single my ui convert into like this by above xml code

enter image description here

Now I want to add edittext and button in bottom. Its not working vertical bias. Does any one know how to fix. Any suggestion to what can i use

Expected Output

Scenerio 1

enter image description here

Scenerio 2

enter image description here

Actual Output

enter image description here

I tried this code

<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:background="@color/white">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingStart=10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/crecyclerView">

        <EditText
            android:id="@+id/editTextContainer"
            android:layout_width="200dp"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/button"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/editTextContainer"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

UPDATE

After adding @MartinMarconcini answer it fixed my Scenario 2. I want to fix as Scenario 1 as well.

enter image description here

Kotlin Learner
  • 3,995
  • 6
  • 47
  • 127
  • Set the_ RecyclerView_ height to `0dp`. – Cheticamp Oct 24 '21 at 21:01
  • @Cheticamp it's not working. When item is more the first item in reverse order is showing half cut and if item in one it staying in reverse order. – Kotlin Learner Oct 24 '21 at 21:36
  • @Cheticamp do you have any other suggestions please ? – Kotlin Learner Oct 24 '21 at 21:49
  • What I stated will keep the _RecyclerView_ above the _EditText_ and _Button_ regardless of how many items are in the _RecyclerView_. I must not understand your issue with the layout since that works for me according to my understanding. – Cheticamp Oct 24 '21 at 21:51
  • @Cheticamp It works when i set to 0dp but, I want my recyclerview fill whole height and show expected output in image 1 . – Kotlin Learner Oct 24 '21 at 21:55
  • So, you want the _EditText_ and _Button_ to only appear only if the _RecyclerView_ fills the screen? I am still not sure. – Cheticamp Oct 24 '21 at 22:03
  • @Cheticamp yeah kind of. But expected image is not working when I used 0dp. – Kotlin Learner Oct 24 '21 at 22:09
  • I think you're confusing where the problem is. A RecyclerView is just a ViewGoup (granted, with a lot of other _features_); the RV has to use all _available_ space, regardless of the contents, and the EditText ought to be pinned at the bottom _below_ the RV at all times. The RV will populate its contents together w/ its adapter + layoutManager and ConstraintLayout will be able to measure/layout both (RV + EditText) according to their constraints. – Martin Marconcini Oct 25 '21 at 10:37
  • The RV should use `0dp` on *both* constraints. Match Parent _shouldn't be used_ for Constraint Layout. – Martin Marconcini Oct 25 '21 at 10:38
  • @MartinMarconcini i got your point. can you give me example please? – Kotlin Learner Oct 25 '21 at 10:41
  • See updated answer. – Martin Marconcini Oct 25 '21 at 10:52

1 Answers1

1

The idea is that your RV will handle its own item size and space by itself. You don't need to worry about this.

The Remainder of the space, will be used by ConstraintLayout.

So you need to pin the RV and the "Bottom Container" together. This would by default cause the CL to try to pull and balance layouts, so you have to tell the bottom container to be biased at the bottom.

In pseudo-XML:

<ConstraintLayout>
   <RecyclerView 
      width=0dp
      height=0dp
      start/end = parent
      TopToTop=parent
      BottomToTopOf=BottomContainer
   > 
   <BottomContainer>
      width=0dp
      height=wrap_content 
      TopToBottomOf=RecyclerView
      BottomToBottomOf=parent
      start/end = parent>
</ConstraintLayout>

Now this needs one more thing, because the RV would take all the space, you want to ensure the BottomContainer has more information about where it wants to be placed.

So you add:

app:layout_constraintVertical_bias="1.0"

to the Bottom Container.

This means, vertically, as "bottom" as you can. (0.0 would be the opposite).

The end result is:

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

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recylerview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@android:layout/simple_list_item_2" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="0dp"
        app:layout_constraintVertical_bias="1.0"
        android:layout_height="wrap_content"
        android:id="@+id/bottomContainer"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/recylerview"
        app:layout_constraintBottom_toBottomOf="parent">

        <EditText
            android:id="@+id/editTextContainer"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/button"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/editTextContainer"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Which looks like this:

Image of an Android screen in Android Studio editor with a Recycler View with sample items and an edit text and button pinned at the very bottom, similar to a chat application.

UPDATE

If you add both

  app:stackFromEnd="true"
  app:reverseLayout="true"

It works the same way, except the item "0" is at the bottom, and the "last" item is at the top. Adding another item would add it at the top but the BottomContainer has no participation (or influence) over this:

Image of an Android screen in Android Studio editor with a Recycler View with sample items and an edit text and button pinned at the very bottom, similar to a chat application, the items are in reverse order and grow upwards

Martin Marconcini
  • 26,875
  • 19
  • 106
  • 144
  • great answer it works in my **scenario 2**. Can you please help in **scenario 1** you can see image in **Expected output** – Kotlin Learner Oct 25 '21 at 11:01
  • Are you saying this _doesn't_ work when you have "1" item? In the screenshot you can see that there is space below the RV to add more items. It shouldn't matter how many items you have, the RV will "use" all the space, with enough left for the _bottom container_ to be pinned at the bottom. – Martin Marconcini Oct 25 '21 at 11:06
  • yes it's not working because my reyclerview have **reverselayout** and **stackFromEnd** true. It adding element. I am attaching image in few minutes. How it looks like now. – Kotlin Learner Oct 25 '21 at 11:12
  • I added screenshot. please have a look. How to fix that – Kotlin Learner Oct 25 '21 at 11:17
  • So you use `stackFromEnd` so it grows upwards, but you also use `reverseLayout` so it grows from top to bottom? Is the new image what you see or what you want? – Martin Marconcini Oct 25 '21 at 11:28
  • I see updated image now, though I want to see **Scenerio 1** as my expected output. – Kotlin Learner Oct 25 '21 at 11:50
  • 1
    Got it I got your answer. Thanks a million @MartinMarconcini – Kotlin Learner Oct 25 '21 at 12:02
  • I need your help on this please. do you know how to solve this [example](https://stackoverflow.com/q/69715381/11560810) – Kotlin Learner Oct 25 '21 at 22:59