【问题标题】:After refreshing data, the RecyclerView seems to move down on the screen刷新数据后,RecyclerView 似乎在屏幕上向下移动
【发布时间】:2019-10-11 16:35:00
【问题描述】:

使用 LiveData 显示命中 Room 数据库的回收器视图。当我在屏幕上进行搜索时,返回的项目数量较少,但是,回收站视图和其他按钮之间似乎有很多额外的空白。回收站视图本身会缩小,然后在屏幕上向下移动。

这是刷新数据之前(在我进行搜索之前)的外观:

后面是:

这是我的 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
        }


}

这是我设置 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()
}

这是我观察适配器的地方:

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

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

    })

这是回收站视图的布局

<?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>

有人见过这样的事情吗?我还确保我在我的 recyclerview 布局和 item.xml 文件中使用了 layout_height = wrap_content。

屏幕截图检查器:

【问题讨论】:

  • Android Studio 的 Layout Inspector 在那个空白区域显示了什么?总体而言有些奇怪,因为您在 RecyclerView 上的上边距有 75dp。您的第一个屏幕截图似乎没有显示该边距,而您的第二个屏幕截图显示的空白比75dp 多得多。
  • @CommonsWare 它实际上显示空白处没有发生任何事情。无论搜索结果如何,屏幕中回收站视图的上边距(layout_topmargin)始终保持在 197。但是,recyclerView 的 Properties Table -> layout 下的 mTop 属性显示后搜索结果为 547,所有结果为 236。 mTop 不是公共财产,所以我不知道这个数字是怎么计算出来的。
  • mTop是根据布局规则,反映实际位置。在您的布局中,RecyclerView 顶部边缘锚定到 btnFilterBy 的底部。你确定btnFilterBy 没有延伸到那个空白空间吗?
  • @CommonsWare btnFilterBy 绝对不会扩展到该视图。更新了我的问题以显示布局检查器的屏幕截图。
  • 好的,我无法解释为什么你会得到你现在的结果。就个人而言,我会设置一个Barrier 代表您的按钮行(排序、下降、过滤器)的底部,并让RecyclerView 将其顶部连接到Barrier。这涵盖了您,以防其中一个按钮由于语言翻译和小屏幕尺寸的某种组合而最终比其他两个高。从理论上讲,这也可能有助于您的空白情况。否则,纵轴有什么不寻常的地方吗?例如,你有一些下拉刷新代码吗?

标签: android android-recyclerview android-livedata pagedlist


【解决方案1】:

好的,看起来我已将 recyclerview layout_constraintBottom_toBottomOf 设置为“父级”,并且由于 recyclerview 的总高度在项目数量缩小时缩小了,因此它正在将视图移动到屏幕底部。我还可以摆脱顶部边距属性,并且回收站视图保持在按钮下方。所以现在我有:

    <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"/>

一切看起来都不错!

【讨论】:

  • 我是个白痴,并没有注意到wrap_content 的高度。 wrap_content 对于具有不同内容的事物的高度很少是一个好主意(例如,ListViewRecyclerViewScrollView)。因此,另一种方法是恢复底部锚点,但将高度设置为 0dp,以在顶部和底部锚点之间拉伸 RecyclerView。此外,理想情况下,将宽度设置为 0dp 以在起点和终点锚点之间伸展,因为从技术上讲,match_parent 不支持 ConstraintLayout 的子级。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 2013-09-16
相关资源
最近更新 更多