Search code examples
androidkotlinandroid-layoutandroid-recyclerviewandroid-constraintlayout

Set proper constraint in Constraint Layout in Android Kotlin


I am creating a chat application. I used stackFromEnd = false and reverseLayout = true to show items from the bottom of screen. In which I used reyclerview and it's working fine, and I am adding the code below with a screenshot. How it looks likes

<?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"
    android:background="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        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>

The above code is working fine when there is a single item in recyclerView it opens a screen like this

Image 1

Example1

But when there are more items the screen look like this

Image 2

enter image description here

Note: This above image is my expected output. Also soft keyboard shift the layout.

Now the main story starts, I want to add editText at bottom of the screen.

<?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="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        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_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="0dp"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:visibility="gone"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/conversationRecyclerView"
        app:layout_constraintVertical_bias="1.0">

        <EditText
            android:id="@+id/edittext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inputType="textMultiLine|text|textNoSuggestions"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Problem 1

Image 1 is not getting the correct constraint and it looks like this

enter image description here

and image 2 is working fine and the soft keyboard shifts the layout.

problem 2

I tried some code to solve problem 1 and the soft keyboard is not shifting the layout

<?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="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:paddingBottom="10dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constrainedHeight="true"
        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="0dp"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintVertical_bias="1.0">

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

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

UPDATE

After @Cheticamp suggestion, I added this but not working. It has still a problem 1 issue. It's not resolving.

<?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="#cccccc">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/conversationRecyclerView"
        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_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
      >

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

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

UPDATE 1

After @Tenfour04 suggestions, I added some code please have a look. Am I am doing correctly?

<?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="#cccccc">

    <FrameLayout
        android:id="@+id/conversationRecyclerViewViewWrapper"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/conversationRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:paddingBottom="10dp"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

    </FrameLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/inputContainer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:paddingStart="10dp"
        android:paddingTop="14dp"
        android:paddingEnd="10dp"
        android:paddingBottom="14dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/conversationRecyclerView">

        <EditText
            android:id="@+id/sendMessageEditText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:inputType="textMultiLine|text|textNoSuggestions"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • The problem is your RecyclerView's height is wrap_content instead of 0dp (a.k.a. "match_constraints"), so it ignores the constraint that it should be above inputContainer.

    So instead of making it wrap_content and using vertical bias to try to keep it at the top of the screen, try wrapping it in a FrameLayout and giving it layout gravity of "top". The FrameLayout should use 0dp for height so it can fill the entire space, but not overlap inputContainer. The RecyclerView can use wrap_content for height, and the layout gravity will bias it to the top of the FrameLayout's space. So replace your RecyclerView element with this:

    <FrameLayout
        android:id="@+id/recyclerViewWrapper"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/inputContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/conversationRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:paddingBottom="10dp"
            app:layoutManager="LinearLayoutManager"
            app:reverseLayout="true"/>
    </FrameLayout>
    

    The app:layout_constraintVertical_bias is meaningless on inputContainer because it has no top constraint, so you can remove that.