androidandroid-recyclerviewandroid-livedatapagedlist

After refreshing data, the RecyclerView seems to move down on the screen


Using LiveData<PagedList> to display a recycler view that hits a Room database. When I do a search on screen, the number of items returned is less, however, there seems to be a lot of extra white space between the recycler view and the other buttons. The recycler view itself shrinks, and then moves down on the screen.

Here is the way it looks before the data is refreshed (before I do a search):

normal

Here is after:

white space

Here is my adapter for the recyclerView:

class WorkPackagesRecyclerAdapter(
  private val onWorkPackageClickListener: OnClickWorkPackage
   ) : PagedListAdapter<Workpackage, 
 WorkPackagesRecyclerAdapter.WorkPackagesViewHolder>(
  REPO_COMPARATOR
) {


interface OnClickWorkPackage {
    fun clickWorkPackage(workPackageId: String)
}

override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): WorkPackagesViewHolder {
    val inflater = LayoutInflater.from(viewGroup.context)
    val binding = inflate<ItemWorkPackageBinding>(
        inflater,
        R.layout.item_work_package,
        viewGroup,
        false
    )
    return WorkPackagesViewHolder(binding, viewGroup.context)
}


override fun onBindViewHolder(holder: WorkPackagesViewHolder, position: Int) 
{

    getItem(position)?.let {
        holder.bind(it)
    }

}

inner class WorkPackagesViewHolder(
    internal var binding: ItemWorkPackageBinding,
    internal val context: Context
) : RecyclerView.ViewHolder(binding.root), KoinComponent {

    fun bind(data: Workpackage) {
        val itemWorkPackagesViewModel: ItemWorkPackagesViewModel by inject{ parametersOf(data)}
        this.binding.listItem.setOnClickListener {
            onWorkPackageClickListener.clickWorkPackage(data.id)
        }
        this.binding.viewmodel = itemWorkPackagesViewModel
        this.binding.executePendingBindings()
    }

}

companion object {
    private val REPO_COMPARATOR =
        object : DiffUtil.ItemCallback<Workpackage>() {
            override fun areItemsTheSame(
                oldItem: Workpackage,
                newItem: Workpackage
            ): Boolean =
                oldItem.id == newItem.id

            override fun areContentsTheSame(
                oldItem: Workpackage,
                newItem: Workpackage
            ): Boolean =
                oldItem == newItem
        }


}

Here is how I set up the PagedList:

val searchQuery: MutableLiveData<SearchAndSort> = MutableLiveData(
    SearchAndSort("",
        WorkpackagesRepository.Companion.SortedBy.WorkPackageNumber,
        AscendDescend.ASC))

var workPackagesList = Transformations.switchMap(searchQuery) { searchQuery ->
    val factory = workPackageStorageDao.searchWorkpackages(
        searchQuery.searchText,
        searchQuery.sortBy.type + " " + searchQuery.ascendDescend.text
    )
    val pagedListBuilder = LivePagedListBuilder<Int, Workpackage>(factory, pagingLimit)
    pagedListBuilder.build()
}

Here is where I am observing the adapter:

    workPackagesViewModel.workPackagesList.observe(this, Observer { wpList ->
        wpList ?: return@Observer

        adapter = WorkPackagesRecyclerAdapter(this)
        adapter.submitList(wpList)
        binding.workPackagesRecyclerView.adapter = adapter
        adapter.notifyDataSetChanged()

    })

Here is the layout of the recycler view

<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>

    <variable
        name="viewModel"
        type="com.bechtel.pf.ui.workpackages.WorkPackagesViewModel" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="727dp"
    tools:layout_editor_absoluteY="1dp">

    <EditText
        android:id="@+id/search_bar_edit_text"
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:layout_marginTop="@dimen/work_package_margin"
        android:hint="@string/work_packages_search_hint"
        app:layout_constraintBottom_toBottomOf="@id/guideline"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <ImageButton
        android:id="@+id/search_bar_magnifying_glass"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_marginTop="@dimen/work_package_margin"
        android:background="@drawable/icons_search"
        app:layout_constraintBottom_toBottomOf="@id/guideline"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="@dimen/work_package_search_guideline_start"

        />
    <com.google.android.material.button.MaterialButton
        android:id="@+id/btnSortBy"
        android:layout_width="0dp"
        android:layout_height="45dp"
        android:layout_marginTop="5dp"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:backgroundTint="@color/colorPrimary"
        app:layout_constraintEnd_toStartOf="@+id/btnAscendDescend"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/guideline"
        app:layout_constraintHorizontal_chainStyle="spread"
        android:text="@string/work_packages_sort"
        />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/btnAscendDescend"
        android:layout_width="0dp"
        android:layout_height="45dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"
        android:backgroundTint="@color/colorPrimary"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintEnd_toStartOf="@+id/btnFilterBy"
        app:layout_constraintStart_toEndOf="@+id/btnSortBy"
        app:layout_constraintTop_toBottomOf="@+id/guideline"
        app:layout_constraintHorizontal_chainStyle="spread"
        android:text="@string/work_packages_ascend"
        android:onClick="@{() -> viewModel.ascendingDescending()}"
        />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/btnFilterBy"
        android:layout_width="0dp"
        android:layout_height="45dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"
        android:backgroundTint="@color/colorPrimary"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btnAscendDescend"
        app:layout_constraintTop_toBottomOf="@+id/guideline"
        android:text="@string/work_packages_filter"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/workPackagesRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"
        android:layout_marginTop="75dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnFilterBy">

    </androidx.recyclerview.widget.RecyclerView>


</androidx.constraintlayout.widget.ConstraintLayout>

Anyone ever seen anything like this before? I've also made sure that I am using layout_height = wrap_content in my recyclerview layout and item.xml files.

Screenshot inspector:

layout inspector


Solution

  • OK, it looks like I had set the recyclerview layout_constraintBottom_toBottomOf was set to 'parent' and since the total height of the recyclerview shrunk when the number of items shrunk, it was moving the view to the bottom of the screen. I also could get rid of the top margin attribute and the recycler view stayed below the buttons. So now I have:

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/workPackagesRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/btnFilterBy"/>
    

    And it all looks good!