5

I want to document the problems I ran into and the solution for the benefit of others, and find help with the key flaw in my solution.

I want a RecyclerView with an arbitrary number of rows in a layout with a number of other Views. The RecyclerView and other Views should be in a ScrollView that scrolls, but the RecyclerView itself should not scroll.

Since the number of rows in the RecyclerView is unknown, and I'm required to have other views immediately underneath the RecyclerView, I can't use a fixed height or match_parent.

I experienced some odd problems: when I would update the RecyclerView data (using an AsyncListDiffer) and the UI was supposed to update, the entire RecyclerView would jump above the view it was constrained underneath, straight to the top of the parent. This is not how a ConstraintLayout is supposed to behave.

Then I was able to stop that from happening, but Views underneath the RecyclerView would disappear--appearing once the RecyclerView data updated.

The solution:

  1. Put the RecyclerView and other Views inside a ConstraintLayout inside a ScrollView (or NestedScrollView)
  2. Set the RecyclerView to have a height of wrap_content (and adding app:layout_constrainedHeight="true" doesn't hurt)
  3. Make sure the rows in the RecyclerView have a fixed height and do not have a height of wrap_content

This was helpful to me after banging my head against the wall and trying some proposed solutions that did not work: make RecyclerView's height to "wrap_content" in Constraint layout

This solution is pretty simple. The layout can be something like:

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

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

            <!-- other Views -->

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/otherView"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toTopOf="@+id/anotherView"
                />

                <!-- other Views -->
        </androidx.constraintlayout.widget.ConstraintLayout>

    </ScrollView>

And then the layout for a row:

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

<!-- other views -->

</androidx.constraintlayout.widget.ConstraintLayout>

Here's the problem: I'm not a fan of fixed-height rows. What if other content needs to go in there? What if the user changes their text size? I much prefer flexible layouts that can adapt in size. But if I do that, then the RecyclerView takes up a screen's worth of height inside the ScrollView, shoving all lower views off the bottom of the screen, no matter how few rows it contains.

The alternatives I can think of are to make all the other Views outside the RecyclerView become rows of the RecyclerView, or to avoid a RecyclerView altogether and programmatically add Views to a LinearLayout. These are much uglier approaches.

Is there a way to fix it so the rows of the RecyclerView can have a height of wrap_content?

Chad Schultz
  • 7,770
  • 6
  • 57
  • 96
  • The solution I always use for such case is recycler view with different view types. Why ugly? – Derek K Feb 16 '19 at 13:18
  • 1
    note: if you set `android:layout_height="0dp"` on your ScrollView, then you should set `app:layout_constraintBottom_toBottomOf="parent"`, and if you don't then your scrollview will never be visible because it will always be 0dp height unless you constraint the Top and Bottom. I'm upvoting your question/answer because it helped me solve the same issue. thanks. concerning rows in recyclerviews, I don't use contraint layouts for that, usually I use Relative or LinearLayouts with height to wrap_content. other note: I use `android:nestedScrollingEnabled="false"` on recyclerview to fix the scroll. – Raphael C May 26 '20 at 13:30

0 Answers0