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):
Here is after:
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:
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!