1

I have a RecyclerView and GridLayoutManager with 2 columns. Items are populated with DiffUtil and everything works fine so far. The items consist of an image (always the same height) and a text, which can vary in length and has therefore an dynamic heigth.

The GridLayoutManager seems to arrange each item of a row with the same height. But it´s not recalculating them once they´re changing rows -> height of a cell remains static as long as they are currently visible.

Example: 6 Items in total.

 A | B
 C | D 
 E | F 

So if item E has a short text, lets say height 100, and item F has a long text, heigt 500, both items semms to have the height of 500.

If item B gets deleted, E is changing the row from 3 to 2, but still has height 500 and item D may have only 150. E has then "350 too much height". This creates a strange look, as there is then a lot of white space between row 2 and 3...

Once you scroll (= those items are not visible anymore) an scroll back, everything is measured fine again.

How can I solve this problem?

Thanks for your help.

Update:

item.xml:

    <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
<LinearLayout
    android:id="@+id/items_folder_item_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusable="true"
    android:paddingTop="15dp"
    android:paddingStart="10dp"
    android:paddingEnd="10dp"
    android:paddingBottom="15dp"
    android:background="?android:attr/selectableItemBackground"
    android:orientation="horizontal">
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_weight="1">
        <RelativeLayout
            android:layout_width="127dp"
            android:id="@+id/items_folder_item_folder_container"
            android:layout_gravity="center_horizontal"
            android:layout_height="127dp">
            <ImageView
                android:id="@+id/items_folder_item_folder"
                android:layout_width="127dp"
                android:layout_height="127dp"
                android:src="@{folder.homeFolder ? (folder.homeIconType == 1 ? @drawable/ic_ordner_weis : (folder.homeIconType == 2 ? @drawable/ic_navi_bons : @drawable/ic_home_grey_48px)) : @drawable/ic_ordner_weis }"
                android:tint="@{folder.folderColorCode}"
                android:contentDescription="@null" />

            <ImageView
                android:layout_width="17dp"
                android:layout_height="17dp"
                android:contentDescription="@null"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="30dp"
                android:layout_marginStart="24dp"
                android:visibility="@{item.selectionMode ? selectedFolders.contains(item)  View.GONE : View.VISIBLE : View.GONE}"
                android:src="@drawable/ic_item_selection_placeholder" />

            <ImageView
                android:layout_width="27dp"
                android:layout_height="27dp"
                android:contentDescription="@null"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="27dp"
                android:layout_marginStart="22dp"
                android:visibility="@{selectedFolders.contains(item) == true ? View.VISIBLE : View.GONE}"
                android:src="@drawable/ic_item_selected" />

        </RelativeLayout>

        <LinearLayout
            android:id="@+id/items_folder_item_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:orientation="horizontal">

                <ImageView
                    android:layout_width="16dp"
                    android:layout_height="16dp"
                    android:layout_marginEnd="9dp"
                    android:layout_gravity="center_vertical"
                    android:src="@{item.item.visibleToContact ? @drawable/ic_shared : @drawable/ic_shared_in_progress}"
                    android:visibility="@{item.item.itemPermitted ? View.VISIBLE : View.GONE}"
                    android:contentDescription="@null" />

                <ImageView
                    android:layout_width="16dp"
                    android:layout_height="16dp"
                    android:layout_marginEnd="7dp"
                    android:layout_gravity="center_vertical"
                    android:visibility="@{folder.folderIsFavorite == true ? View.VISIBLE : View.GONE}"
                    android:src="@drawable/ic_favorite_set"
                    android:contentDescription="@null" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="center_horizontal"
                    style="@style/ItemNameGrid"
                    android:textColor="@{selectedFolders.contains(item) ? @color/gridItemSelectedTextColor : @color/brownGreyText}"
                    android:text="@{folder.folderName}" />
            </LinearLayout>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:visibility="@{folder.homeFolder ? View.GONE : View.VISIBLE}"
                style="@style/ItemInfoTextGrid"
                android:textColor="@{selectedFolders.contains(item) ? @color/gridItemSelectedTextColor : @color/bluishGreyText}"
                android:text='@{folder.folderItemCount == 1 ? String.format(@string/items_item_element, folder.folderItemCount) : String.format(@string/items_item_elements, folder.folderItemCount) }' />

        </LinearLayout>
    </LinearLayout>

    <RelativeLayout
        android:id="@+id/items_folder_item_more_container"
        android:layout_width="37dp"
        android:clickable="true"
        android:focusable="true"
        android:layout_gravity="bottom"
        android:visibility="@{inChoosingMode ? folder.homeFolder ? View.INVISIBLE : View.VISIBLE : item.selectionMode ? View.INVISIBLE : View.VISIBLE}"
        android:layout_height="37dp">

        <ImageView
            android:layout_width="27dp"
            android:layout_height="27dp"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"
            android:background="?selectableItemBackgroundBorderless"
            android:src="@{inChoosingMode ? @drawable/ic_arrow_right : @drawable/ic_more}"
            android:contentDescription="@null" />

    </RelativeLayout>

</LinearLayout>
</RelativeLayout>

RecyclerView layout:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:background="@color/defaultBackgroundColor"
android:id="@+id/items_root">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:layout_width="match_parent"
    android:id="@+id/items_refresh_layout"
    android:layout_height="match_parent">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/items_content">


            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="22dp"
                android:layout_marginTop="20dp"
                android:layout_marginStart="22dp"
                android:id="@+id/items_topbar">

                <com.fm.atmin.controls.sortfilter.sort.SortControl
                    android:id="@+id/items_topbar_sort_control"
                    android:layout_width="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_height="wrap_content" />

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:clickable="true"
                    android:background="?android:attr/selectableItemBackground"
                    android:layout_alignParentEnd="true"
                    android:id="@+id/items_view_mode_container"
                    android:focusable="true">

                    <ImageView
                        android:id="@+id/items_view_mode"
                        android:layout_width="27dp"
                        android:layout_height="27dp"
                        android:src="@drawable/ic_view_module_grid"
                        />
                </LinearLayout>

            </RelativeLayout>

            <androidx.recyclerview.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/items_recyclerview"
                android:layout_below="@id/items_topbar"
                android:layout_marginTop="25dp" />
        </RelativeLayout>
        <include
            layout="@layout/items_no_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"/>

        <include
            layout="@layout/no_network_layout"
            android:visibility="gone"/>
    </RelativeLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

1 Answers1

0

I ran into the same issue; fixed it by adding some code to RecyclerView.Adapter.onBindViewHolder.

override fun onBindViewHolder(holder:ItemVH,position:Int)
{
    // do the binding
    ......

    // after binding item to view holder, request UI to re-layout items
    holder.itemView.requestLayout()
}

see the documentation for requestLayout()

Call this when something has changed which has invalidated the layout of this view. This will schedule a layout pass of the view tree. This should not be called while the view hierarchy is currently in a layout pass (isInLayout(). If layout is happening, the request may be honored at the end of the current layout pass (and then layout will run again) or after the current frame is drawn and the next layout occurs.

Subclasses which override this method should call the superclass method to handle possible request-during-layout errors correctly.

If you override this method you must call through to the superclass implementation.

Eric
  • 16,397
  • 8
  • 68
  • 76