如何滚动到底部的回收视图? scrollToposition 不工作

我想在加载活动后滚动到回收视图列表的底部。

GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);

conversationView.scrollTo(...)抛出一个异常,说明回收视图不支持 conversationView.scrollToPosition(...),而 conversationView.scrollToPosition(...)似乎什么也不做。

在上面的代码块之后,我添加了

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)

这不管用。 GENERIC_MESSAGE_LIST里有30种元素。

218829 次浏览

当您调用 setAdapter时,它不会立即在屏幕上布局和定位项(只需要一次布局传递) ,因此当您调用 scrollToPosition()时,没有实际的元素可以滚动到。

相反,你应该注册一个 OnGlobalLayoutListener(通过 AddOnGlobalLayoutListner ()conversationView.getViewTreeObserver()创建的 ViewTreeObserver) ,它会延迟你的 scrollToPosition(),直到第一次布局通过之后:

conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
// Unregister the listener to only call scrollToPosition once
conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);


// Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as
// removeGlobalOnLayoutListener is deprecated.
// They do the same thing, just a rename so your choice.
}
});
class MyLayoutManager extends LinearLayoutManager {


public MyLayoutManager(Context context) {
super(context, LinearLayoutManager.VERTICAL, false);
}


@Override public void smoothScrollToPosition(RecyclerView recyclerView,
final RecyclerView.State state, final int position) {


int fcvip = findFirstCompletelyVisibleItemPosition();
int lcvip = findLastCompletelyVisibleItemPosition();


if (position < fcvip || lcvip < position) {
// scrolling to invisible position


float fcviY = findViewByPosition(fcvip).getY();
float lcviY = findViewByPosition(lcvip).getY();


recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {


int currentState = RecyclerView.SCROLL_STATE_IDLE;


@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {


if (currentState == RecyclerView.SCROLL_STATE_SETTLING
&& newState == RecyclerView.SCROLL_STATE_IDLE) {


// recursive scrolling
smoothScrollToPosition(recyclerView, state, position);
}


currentState = newState;
}


@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {


int fcvip = findFirstCompletelyVisibleItemPosition();
int lcvip = findLastCompletelyVisibleItemPosition();


if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
// stop scrolling
recyclerView.setOnScrollListener(null);
}
}
});


if (position < fcvip) {
// scroll up


recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
} else {
// scroll down


recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
}
} else {
// scrolling to visible position


float fromY = findViewByPosition(fcvip).getY();
float targetY = findViewByPosition(position).getY();


recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
}
}
}

还有

MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);


RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);


recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);

上面的代码可以工作,但是它不流畅,也不酷。

我看着这个帖子寻找答案,但是... ... 我认为这个帖子上的每个人都面临着和我一样的情况: scrollToPosition()被完全忽略了,原因很明显。

我用的是什么?

recyclerView.scrollToPosition(items.size());

什么 成功了

recyclerView.scrollToPosition(items.size() - 1);

只需设置 setStackFromEnd=truesetReverseLayout=true,这样 LLM 就可以从结束开始布局项目。

这两者之间的区别在于,setStackFromEnd将设置视图来显示最后一个元素,布局方向将保持不变。(因此,在从左到右的水平回收视图中,将显示最后一个元素,向左滚动将显示较早的元素)

setReverseLayout将改变适配器添加的元素的顺序。布局将从最后一个元素开始,这将是 LTR 回收视图中最左边的元素,然后向右滚动将显示较早的元素。

样本:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);

详情请参阅 文件

从回收视图中的任何位置向下滚动到底部

科特林

editText.setOnClickListener {
rv.postDelayed({
rv.scrollToPosition(rv.adapter.itemCount - 1)
}, 1000)
}

爪哇咖啡

edittext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
rv.postDelayed(new Runnable() {
@Override
public void run() {
rv.scrollToPosition(rv.getAdapter().getItemCount() - 1);
}
}, 1000);
}
});

我知道现在回答这个问题已经晚了,但是如果有人想知道答案的话还是在下面

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);

只有伊恩的答案才能使我的 RecyclerView滚动到指定的位置。然而,当我使用 scrollToPosition()时,RecyclerView无法在后面滚动。smoothScrollToPosition()工作,但最初的动画使它太慢时,列表很长。 原因是监听器没有被删除。我使用下面的代码删除当前的 ViewTreeObserver和它的工作作为一个魅力。

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mRecyclerView.scrollToPosition(mPosition);
mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});

如果你有适配器与回收视图,然后只是这样做。

mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());

Roc 的回答非常有帮助,我想给它加上一个小块:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);

这对我来说完全没问题:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);

在我的情况下,视图没有相同的高度,调用 < strong > scrollToposition on the LayoutManager 工作,真正滚动到底部,并完全看到最后一项:

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);

在 Kotlin:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }


private fun scrollToEnd() =
(adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)

这个代码会给你最新的帖子第一,我认为这个答案是有帮助的。

    mInstaList=(RecyclerView)findViewById(R.id.insta_list);
mInstaList.setHasFixedSize(true);


LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);


mInstaList.setLayoutManager(layoutManager);
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);

在发送消息之后和从服务器获取消息之前添加此代码

recyclerView.scrollToPosition(mChatList.size() - 1);

科特林的解决方案:

在设定「回收视像适配器」或「回收视像适配器适配器通知资料设定改变()」后,以下列程式码应用

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)

尝试了 @ galex的一种方法,它一直工作到重构。所以我用了一个 @ yanchenko的答案,并做了一点改动。这可能是因为我从构建片段视图的 onCreateView()调用了滚动(可能没有合适的大小)。

private fun scrollPhotosToEnd(view: View) {
view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
} else {
@Suppress("DEPRECATION")
view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
}
adapter?.itemCount?.takeIf { it > 0 }?.let {
view.recycler_view.scrollToPosition(it - 1)
}
}
})
}

您还可以像在 https://stackoverflow.com/a/39001731/2914140中那样添加 viewTreeObserver.isAlive检查。

第一次滚动时进入回收视图第一次然后使用

linearLayoutManager.scrollToPositionWithOffset(messageHashMap.size()-1

放入负值,向下滚动,向上滚动,放入正值) ;

如果视图的高度非常大,那么在视图顶部使用滚动位置特定偏移量,然后使用

int overallXScroldl =chatMessageBinding.rvChat.computeVerticalScrollOffset();
chatMessageBinding.rvChat.smoothScrollBy(0, Math.abs(overallXScroldl));

如果这些都不管用,

你应尝试使用:

ConstraintLayout targetView = (ConstraintLayout) recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount()-1).itemView;
targetView.getParent().requestChildFocus(targetView, targetView);

通过这样做,你要求一个特定的 ConstraintLayout (或者你有的任何东西)显示。

我的工作,甚至与键盘显示。

如果你正在使用他,你必须在 scrollToPosition之前隐藏 AppBarLayout

答案是

recyclerView.scrollToPosition(arrayList.size() - 1);

每个人都提到过。

但是我所面临的 问题位置不对

我尝试和放置后,刚刚 adapter.notifyDataSetChanged();和它的工作。 只要回收器视图中的数据发生变化,它就会自动滚动到底部,就像发送消息之后或者第一次打开聊天列表时那样。

注意: 这段代码是用 Java 编写的。

我的真实代码是:

//scroll to bottom after sending message.
binding.chatRecyclerView.scrollToPosition(messageArrayList.size() - 1);

您可以滚动到最后一个项目的底部,如果最后一个项目的高度太大,您需要偏移

 private void scrollToBottom(final RecyclerView recyclerView) {
// scroll to last item to get the view of last item
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
final int lastItemPosition = adapter.getItemCount() - 1;
    

layoutManager.scrollToPositionWithOffset(lastItemPosition, 0);
recyclerView.post(new Runnable() {
@Override
public void run() {
// then scroll to specific offset
View target = layoutManager.findViewByPosition(lastItemPosition);
if (target != null) {
int offset = recyclerView.getMeasuredHeight() - target.getMeasuredHeight();
layoutManager.scrollToPositionWithOffset(lastItemPosition, offset);
}
}
});






}

如果你想从最终开始使用:

layoutManager.stackFromEnd = true

(Kotlin 溶液)

如果在使回收视图滚动到最新版本时遇到问题,请检查回收视图不在 nestedScrollView 中。那是我的问题。我必须删除 nestedScrollview,然后下面的代码就可以工作了。

binding.recyclerView.scrollToPosition(adapter.getItemCount() - 1);

我知道这是太晚了,但这对我工作,所以我回答这个问题

首先,

LinearLayoutManager layoutManager=new LinearLayoutManager(this);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);

之后,

database.addValueEventListener(....){
@override
public void onDataCange(...){
....
....
//put this line here
recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount()-1);
}
}

只用重力便于解决

机器人:

如果你用 Kotlin 试试这个

conversationView.post {
scrollToPosition(conversationView?.adapter.itemCount - 1)
}

如果你使用反向布局“聊天界面”,特别是如果你有图片,你可以尝试以下方法:

首先,向适配器注册 DataObserver

   chatAdapter.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {


override fun onItemRangeInserted(positionStart: Int itemCount: Int) {


val messageCount: Int = chatAdapter.itemCount


val lastVisiblePosition: Int =
layoutManager.findLastCompletelyVisibleItemPosition()


if (lastVisiblePosition == -1 || positionStart <= (messageCount - 1)) {
recyclerView.scrollToPosition(positionStart)
}
}
})

一旦为适配器设置了数据,就会调用这个函数

其次,您必须像下面这样向回收视图添加一个滚动监听器:

   recyclerView.addOnScrollListener(object
:RecyclerView.OnScrollListener() {


override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy:
Int) {
super.onScrolled(recyclerView, dx, dy)


val lastVisiblePosition: Int =
layoutManager.findLastCompletelyVisibleItemPosition()
if (lastVisiblePosition != -1 && lastVisiblePosition <
chatAdapter.itemCount - 1) {
recyclerView.smoothScrollToPosition(0)
}
}
})