RecyclerView 应与 stackFromEnd 保持在底部
Posted
技术标签:
【中文标题】RecyclerView 应与 stackFromEnd 保持在底部【英文标题】:RecyclerView should stay at bottom with stackFromEnd 【发布时间】:2021-06-04 09:13:26 【问题描述】:所以基本上这个问题已经存在于网络上:如何让我的RecyclerView
滚动到底部并显示新项目?几乎总能找到答案:添加stackFromEnd=true
或reverseLayout=true
。就我而言,我尝试了两者的所有可能组合,但它没有奏效。我还看到了这样的解决方案:
viewAdapter.registerAdapterDataObserver(object : AdapterDataObserver()
override fun onItemRangeInserted(positionStart: Int, itemCount: Int)
//(layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(viewAdapter.itemCount - 1, 0) or
//(layoutManager as? LinearLayoutManager)?.smoothScrollToPosition(this@ChatMessagesList, null, viewAdapter.itemCount - 1) or
//this@ChatMessagesList.smoothScrollToPosition(viewAdapter.itemCount - 1)
)
这也没有帮助我。首先我将描述我的设置,然后描述预期的行为和当前行为:
我有一个如下所示的 xml:
<merge 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:id="@+id/root_view"
android:layout_
android:layout_
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<ImageView
android:id="@+id/backgroundImage"
android:layout_
android:layout_
android:contentDescription="@string/image_image_description"
android:scaleType="centerCrop"
android:src="@drawable/chat_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/overlay"
android:layout_
android:layout_
android:background="#CCFFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<app.jooy.messenger.ui.components.generic.chat.chat_header.ChatHeader
android:id="@+id/chat_header"
android:layout_
android:layout_
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<app.jooy.messenger.ui.components.generic.chat.chat_message_list.ChatMessagesList
android:id="@+id/chat_messages_list"
android:layout_
android:layout_
app:layout_constraintBottom_toTopOf="@id/chat_options_chooser"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chat_header" />
<app.jooy.messenger.ui.components.generic.chat.chat_options_chooser.ChatOptionsChooser
android:id="@+id/chat_options_chooser"
android:layout_
android:layout_
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/chat_emoji_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<app.jooy.messenger.ui.components.generic.chat.chat_emoji_bar.ChatEmojiBar
android:id="@+id/chat_emoji_bar"
android:layout_
android:layout_
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/chat_action_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<app.jooy.messenger.ui.components.generic.chat.chat_action_bar.ChatActionBar
android:id="@+id/chat_action_bar"
android:layout_
android:layout_
android:background="@color/colorActionBarBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</merge>
重要的视图是chat_messages_list RecyclerView
,这是我的RecyclerView
,其实现如下(为简单起见删除了一些内容):
@ExperimentalCoroutinesApi
@ReactiveComponent
class ChatMessagesList @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ReactiveRecyclerView<ChatMessagesList.ViewState, ChatMessagesList.ViewAction, ChatMessagesList.ViewStructure>(
ViewState(),
context,
attrs,
defStyleAttr
)
private val viewAdapter = ChatMessagesListAdapter()
init
setHasFixedSize(true)
layoutManager = object : LinearLayoutManager(context)
init
stackFromEnd = true
viewAdapter.registerAdapterDataObserver(object : AdapterDataObserver()
override fun onItemRangeInserted(positionStart: Int, itemCount: Int)
//(layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(0, 0)
//(layoutManager as? LinearLayoutManager)?.smoothScrollToPosition(this@ChatMessagesList, null, viewAdapter.itemCount - 1)
//this@ChatMessagesList.smoothScrollToPosition(0)
)
registerTypes(viewAdapter)
adapter = viewAdapter
addItemDecoration(getDecoration())
setPadding(0, 6.toPx(), 0, 6.toPx())
clipToPadding = false
此外,我可以告诉你,我的适配器肯定会调用正确的 notifyItemRangeInserted
, ... 调用。
预期行为:
RecyclerView
应该从屏幕底部的第一个项目开始,并且始终如果添加新项目,则应将其添加到底部并滚动到。最后底部的新项目应该看起来像是从底部推入的。
当前行为:
项目从底部开始堆叠,直到RecyclerView
内的可见空间未满,所有的动画都非常漂亮,但是一旦可见空间已满,项目就会添加到底部但不会滚动到。正如某些人所期望的那样,我想要实现的功能是聊天功能。
补充说明:
如果我将this@ChatMessagesList.smoothScrollToPosition(viewAdapter.itemCount - 1)
添加到onItemRangeInserted
回调中,它会转到底部但没有动画,它只是跳到那里。
【问题讨论】:
【参考方案1】:所以我自己想通了。我仍然不知道为什么某些策略有效,而有些则根本无效。
我在LinearLayoutManager
上设置了reverseLayout=true
(这意味着我必须颠倒列表中的项目),然后我添加了一个onItemRangeInserted
监听器,如下所示:
layoutManager = object : LinearLayoutManager(context)
init
reverseLayout = true
viewAdapter.registerAdapterDataObserver(object : AdapterDataObserver()
override fun onItemRangeInserted(positionStart: Int, itemCount: Int)
if (positionStart == 0)
layoutManager?.scrollToPosition(0)
)
【讨论】:
以上是关于RecyclerView 应与 stackFromEnd 保持在底部的主要内容,如果未能解决你的问题,请参考以下文章
Android,调用 API 14 方法,但应与 API 4 保持兼容
在 UItextfield 的右视图上添加一个按钮,文本不应与按钮重叠