【问题标题】:Loading items into a RecyclerView with stackFromEnd = true doesn't scroll to bottom使用 stackFromEnd = true 将项目加载到 RecyclerView 不会滚动到底部
【发布时间】:2019-08-10 01:52:38
【问题描述】:

我有一个聊天应用程序,我试图确保当用户打开屏幕时,项目从底部显示,最新的项目位于输入区域的正上方。我为输入区域使用了自定义视图,并且回收器和自定义视图都在 ConstraintLayout 中。

我的问题是,当我将项目加载到列表中时,如果项目的数量大于回收器的大小,它不会完全显示最后一个项目。当我使输入区域可见性 = Gone 时,项目会在底部正确显示。这几乎就像回收器 LinearLayoutManager 认为回收器的高度是没有输入字段的屏幕的高度。我已经手动打印出视图的大小并使用布局检查器来确保回收器确实绘制在正确的位置(输入上方和导航栏下方)。

什么可能导致这样的问题?我应该注意,每当您单击聊天气泡中的链接文本时,列表会滚动少量等于打开屏幕时不正确的偏移量。很明显,这里有些东西无法衡量,也不知道从哪里开始。

我还应该注意,如果我尝试使用 smoothScroll 添加帖子,它将转到列表的末尾,但是每当发送消息时列表中出现新项目时,最近添加的项目上方的项目似乎用不必要的动画跳起来一点。好像列表中的最后一项处于某种特殊状态?

如果你好奇,这是我的滚动功能:

private fun scrollToFirstItem(dueToKeyboard: Boolean = false) {
    val stackingFromEnd = (recyclerView.layoutManager as LinearLayoutManager).stackFromEnd

    if (stackingFromEnd) {
        val firstPosition = recyclerView.adapter?.itemCount?: 0 - 1
        if (dueToKeyboard ) {
            recyclerView.scrollBy(0, Integer.MAX_VALUE)
        } else {
            recyclerView.scrollToPosition(firstPosition)
        }
        recyclerView.post { recyclerView.smoothScrollToPosition(firstPosition) }
    } else {
        recyclerView.scrollToPosition(0)
    }
}

还有我的片段的 xml:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<include
        android:id="@+id/searchView"
        layout="@layout/compose_new_message_include"/>

<com.airbnb.epoxy.EpoxyRecyclerView
        android:id="@+id/conversationEpoxyRV"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:scrollbars="vertical"
        app:layout_constraintTop_toBottomOf="@id/searchView"
        app:layout_constraintBottom_toTopOf="@id/composeView"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        tools:listitem="@layout/conversation_item_inbound"/>

<include layout="@layout/conversation_pip_view"
 android:id="@+id/selectedMediaContainer"/>

<****.ComposeView
        android:id="@+id/composeView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

感谢任何帮助,我很迷茫..

【问题讨论】:

  • 提供你的xml文件代码
  • 我也实现了。我只是对你说的话感到困惑。因此,当您发送消息时,您是将该消息附加到同一个列表中还是完全显示为不同的项目?
  • 附加到列表中
  • 实际上最终修复它的是 reverselayout 和 stackfromend 都必须是真的......这有点与文档相反,很明显是一个 android 错误

标签: android android-recyclerview


【解决方案1】:

对我来说,这更像是布局中的问题,而不是滚动功能中的问题。如果您使用 相对布局 而不是 线性布局,我希望可以轻松解决此问题。因此,如果它可能有帮助,我将使用 相对布局 在下面添加我的解决方案。

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

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/input_field">
        </androidx.recyclerview.widget.RecyclerView>

        <EditText
            android:id="@+id/input_field"
            android:layout_width="match_parent"
            android:layout_height="50dp" 
            android:layout_alignParentBottom="true"/>
</RelativeLayout>

所以如果不清楚我做了什么,EditText 元素被设置为与父元素的底部对齐,这是一个相对布局。然后添加一个 RecyclerView 以便 RecylerView 将始终约束在 EditText 之上但不重叠。

【讨论】:

  • 所以我这里其实使用了一个约束布局,也就是一个面向性能的RelativeLayout。展望未来,尽量不要将 RelativeLayout 用于您的任何布局,因为 ConstraintLayout 是新规范
【解决方案2】:

一切看起来都很好,除了您添加到recycleview 设计的限制,我看到您将recycleview 设置在searchView app:layout_constraintTop_toBottomOf="@id/searchView" 的顶部,而searchView 视图不受限制.

最好使用ConstraintLayout 来限制每个视图以避免意外行为,因为每个视图与其他视图有关系将与其他视图(x, y) 影响,因此您的@ 987654327@ 应该是这样的:

<include
    android:id="@+id/searchView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    layout="@layout/compose_new_message_include"/>

【讨论】:

    【解决方案3】:

    将数据数组列表的大小提供给 smoothScrollToPosition

    var linearLayoutManager = LinearLayoutManager(context)
    recyclerView.layoutManager=linearLayoutManager
    recyclerView.adapter=adapter
    linearLayoutManager.setStackFromEnd(true)
    adapter.notifyDataSetChanged()
    recyclerView.smoothScrollToPosition(dataMsgs.size())
    

    【讨论】:

      【解决方案4】:

      几年前我遇到过类似的问题,我用 scrollToPositionWithOffset(支持库)解决了它。当然这是在使用约束之前....

      我也将我的新项目放在底部。插入项目后我用于滚动的代码是:

      ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(getItemCount() - 1, 0);
      

      为了在移除项目后滚动和调整尴尬的位置,我使用了:

      View vTopCard = layoutManager.getChildAt(0);
      // Get its adapter position
      final int topCardPos = layoutManager.getPosition(vTopCard);
      // Get top of card position
      int topOffset = layoutManager.getDecoratedTop(vTopCard);
      int cardMargin = (int) getResources().getDimension(R.dimen.card_vertical_margin);
      
      ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(topCardPos, topOffset - cardMargin);
      

      getDecoratedTop 有助于“反弹”和最终定位,以及考虑垂直边距。

      我希望这会有所帮助(至少是您问题的一部分)!就像我说的,这是旧代码(当我同时学习编写 Android 和 Java 时),所以如果我遗漏了一些东西,请告诉我,我会更详细地重新检查应用程序的代码(不过,我得找时间)。

      祝你好运!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-25
        • 2017-12-21
        • 1970-01-01
        • 2020-09-18
        • 1970-01-01
        • 2021-06-04
        • 1970-01-01
        • 2017-04-09
        相关资源
        最近更新 更多