我正在寻找一种滚动 RecyclerView
以在顶部显示所选项目的方法。
在 ListView
中,我可以通过使用 scrollTo(x,y)
并获取需要居中的元素的顶部来做到这一点。
就像是:
@Override
public void onItemClick(View v, int pos){
mylistView.scrollTo(0, v.getTop());
}
问题是 RecyclerView
在使用它的 scrollTo
方法时返回错误
RecyclerView 不支持滚动到绝对位置
如何滚动 RecyclerView
以将所选项目置于视图顶部?
如果您使用的是 LinearLayoutManager
或 Staggered GridLayoutManager
,它们每个都有一个 scrollToPositionWithOffset 方法,该方法既获取位置,也获取项目起点相对于 RecyclerView
起点的偏移量,看起来像将完成您需要的(将偏移量设置为 0 应与顶部对齐)。
例如:
//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);
如果您正在寻找垂直 LinearLayout 管理器,您可以使用自定义 LinearSmoothScroller
实现平滑滚动:
import android.content.Context;
import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
public class SnappingLinearLayoutManager extends LinearLayoutManager {
public SnappingLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class TopSnappedSmoothScroller extends LinearSmoothScroller {
public TopSnappedSmoothScroller(Context context) {
super(context);
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return SnappingLinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}
在回收视图中使用 layoutmanager 的实例,然后调用 recyclerView.smoothScrollToPosition(pos);
将平滑滚动到回收视图顶部的选定位置
getHorizontalSnapPreference()
。
RecyclerView
的项目?也就是说:这似乎不适用于最后一项 - 无论 SNAP_TO_START
是什么,RecyclerView
只会滚动直到该项目在底部可见,但不会一直向上移动。关于如何实现这一目标的任何想法? (我已经通过在 RecyclerView
上设置自定义填充来解决这个问题,但这似乎并不正确......)
//滚动项目位置
linearLayoutManager.scrollToPositionWithOffset(pos, 0);
您只需调用 recyclerview.scrollToPosition(position)
。没关系!
如果你想在适配器中调用它,只需让你的适配器有recyclerview的实例或包含recyclerview的activity或fragment,然后在其中实现方法getRecyclerview()
。
我希望它可以帮助你。
如果要在不显示滚动动作的情况下自动滚动,则需要编写以下代码:
mRecyclerView.getLayoutManager().scrollToPosition(position);
如果要显示滚动动作,则需要添加以下代码。 =>第1步:您需要声明SmoothScroller。
RecyclerView.SmoothScroller smoothScroller = new
LinearSmoothScroller(this.getApplicationContext()) {
@Override
protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_START;
}
};
=>第2步:您需要将此代码添加到任何要执行滚动到特定位置的事件。 =>首先您需要将目标位置设置为 SmoothScroller。
smoothScroller.setTargetPosition(position);
=>然后你需要将 SmoothScroller 设置为 LayoutManager。
mRecyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
只需简单地调用此方法:
((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(yourItemPosition,0);
代替:
recyclerView.scrollToPosition(yourItemPosition);
与调速器相同
public class SmoothScrollLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 110f;
private Context mContext;
public SmoothScrollLinearLayoutManager(Context context,int orientation, boolean reverseLayout) {
super(context,orientation,reverseLayout);
mContext = context;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext()){
//This controls the direction in which smoothScroll looks for your view
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return new PointF(0, 1);
}
//This returns the milliseconds it takes to scroll one pixel.
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class TopSnappedSmoothScroller extends LinearSmoothScroller {
public TopSnappedSmoothScroller(Context context) {
super(context);
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return SmoothScrollLinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}
试试对我有用的东西很酷!
创建变量 private static int displayedposition = 0;
现在查看 RecyclerView 在 Activity 中的位置。
myRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager llm = (LinearLayoutManager) myRecyclerView.getLayoutManager();
displayedposition = llm.findFirstVisibleItemPosition();
}
});
将此语句放置在您希望它放置在您的视图中显示的先前站点的位置。
LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();
llm.scrollToPositionWithOffset(displayedposition , youList.size());
就是这样,它对我来说很好用\o/
我不知道为什么我没有找到最佳答案,但它真的很简单。
recyclerView.smoothScrollToPosition(position);
没有错误
创建动画
在单击按钮刷新 RecyclerView 后,我做了什么来恢复滚动位置:
if (linearLayoutManager != null) {
index = linearLayoutManager.findFirstVisibleItemPosition();
View v = linearLayoutManager.getChildAt(0);
top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
Log.d("TAG", "visible position " + " " + index);
}
else{
index = 0;
}
linearLayoutManager = new LinearLayoutManager(getApplicationContext());
linearLayoutManager.scrollToPositionWithOffset(index, top);
在创建 linearLayoutManager 对象之前获取第一个可见项的偏移量,并在实例化它之后调用 LinearLayoutManager 对象的 scrollToPositionWithOffset。
我可以在这里补充的是如何使它与 DiffUtil
和 ListAdapter
一起工作
您可能会注意到,如果在 adapter.submitList
之后直接调用,调用 recyclerView.scrollToPosition(pos)
或 (recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, offset)
将不起作用。这是因为diff在后台线程中寻找变化,然后异步通知适配器变化。在一个 SO 上,我看到了几个错误的答案,有不必要的延迟 &等来解决这个问题。
为了正确处理这种情况,submitList
有一个回调,在应用更改时调用该回调。
因此,在这种情况下,正确的 kotlin 实现是:
//memorise target item here and a scroll offset if needed
adapter.submitList(items) {
val pos = /* here you may find a new position of the item or just use just a static position. It depends on your case */
recyclerView.scrollToPosition(pos)
}
//or
adapter.submitList(items) { recyclerView.smoothScrollToPosition(pos) }
//or etc
adapter.submitList(items) { (recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, offset) }
介绍
没有一个答案解释了如何在顶部显示最后一项。因此,答案仅适用于在其上方或下方仍有足够项目来填充剩余 RecyclerView
的项目。例如,如果有 59 个元素并且选择了第 56 个元素,则它应该位于顶部,如下图所示:
https://i.stack.imgur.com/oGfwI.png
那么,让我们在下一段中看看如何实现这一点。
解决方案
我们可以通过使用 linearLayoutManager.scrollToPositionWithOffset(pos, 0)
和 RecyclerView
的 Adapter
中的附加逻辑来处理这些情况 - 通过在最后一项下方添加自定义边距(如果最后一项不可见,则意味着有足够的空间填充 {3 })。自定义边距可能是根视图高度和项目高度之间的差异。因此,您的 RecyclerView
的 Adapter
如下所示:
...
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
...
int bottomHeight = 0;
int itemHeight = holder.itemView.getMeasuredHeight();
// if it's the last item then add a bottom margin that is enough to bring it to the top
if (position == mDataSet.length - 1) {
bottomHeight = Math.max(0, mRootView.getMeasuredHeight() - itemHeight);
}
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)holder.itemView.getLayoutParams();
params.setMargins(0, 0, params.rightMargin, bottomHeight);
holder.itemView.setLayoutParams(params);
...
}
...
如果您的 LayoutManager
是 LinearLayoutManager
,您可以在其上使用 scrollToPositionWithOffset(position,0);
,它将使您的项目成为列表中的第一个可见项目。否则,您可以直接在 RecyclerView
上使用 smoothScrollToPosition
。
我最终使用了下面的代码。
RecyclerView.LayoutManager layoutManager = mainList.getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
// Scroll to item and make it the first visible item of the list.
((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, 0);
} else {
mainList.smoothScrollToPosition(position);
}
在特定位置滚动,这对我有很大帮助。通过单击侦听器,您可以获得适配器中的位置
layoutmanager.scrollToPosition(int position);
在我的情况下,我的 RecyclerView
有一个像这样的填充顶部
<android.support.v7.widget.RecyclerView
...
android:paddingTop="100dp"
android:clipToPadding="false"
/>
然后要将项目滚动到顶部,我需要
recyclerViewLinearLayoutManager.scrollToPositionWithOffset(position, -yourRecyclerView.getPaddingTop());
这很简单
recyclerView.scrollToPosition(position)
我使用下面的代码将项目(thisView)平滑滚动到顶部。它也适用于具有不同高度视图的 GridLayoutManager:
View firstView = mRecyclerView.getChildAt(0);
int toY = firstView.getTop();
int firstPosition = mRecyclerView.getChildAdapterPosition(firstView);
View thisView = mRecyclerView.getChildAt(thisPosition - firstPosition);
int fromY = thisView.getTop();
mRecyclerView.smoothScrollBy(0, fromY - toY);
似乎工作得很好,可以快速解决。
thisPosition
的值是多少?
不定期副业成功案例分享