(平滑)ScrollToPosition 不能与 RecyclerView 一起正常工作
(Smooth)ScrollToPosition doesn't work properly with RecyclerView
我正在使用带有 GridLayoutManager 的基本 RecyclerView。我观察到 smoothScrollToPosition 和 scrollToPosition 都不能正常工作。
a) 当使用 smoothScrollToPosition
时,我经常收到来自 RecyclerView
的错误
"RecyclerView﹕ Passed over target position while smooth scrolling."
和 RecyclerView
没有正确滚动(通常会错过目标行)。这主要是在我试图滚动到某行的第一项时观察到的
b) 当使用 scrollToPosition
时,它似乎工作得很好,但大多数时候我只能看到该行的第一项,其余的没有显示。
你能给我一些提示,告诉我如何至少使其中一种方法正常工作吗?
非常感谢!
调用 recyclerView smoothScroll 无效,因为 recyclerView 本身不处理其布局。
您应该改为调用布局管理器滚动方法。
这应该看起来像这样
mRecyclerView.getLayoutManager().scrollToPosition(desiredPosition);
我终于成功了! LinearLayoutManager.scrollToPositionWithOffset(int, int)
成功了。
单击 EditText 时从 RecyclerView 中的任意位置平滑向下滚动到底部。
edittext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
rv_commentList.postDelayed(new Runnable() {
@Override
public void run() {
rv_commentList.scrollToPosition(rv_commentList.getAdapter().getItemCount() - 1);
}
}, 1000);
}
});
我也有同样的问题,但通过自定义 SmoothScroller 设法解决了这个问题
让 Custom LayoutManager 如下所示
public class CustomLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 50f;
private Context mContext;
public CustomLayoutManager(Context context) {
super(context);
mContext = context;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView,
RecyclerView.State state, final int position) {
LinearSmoothScroller smoothScroller =
new LinearSmoothScroller(mContext) {
//This controls the direction in which smoothScroll looks
//for your view
@Override
public PointF computeScrollVectorForPosition
(int targetPosition) {
return CustomLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
//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);
}
}
(上面给出的代码里面注释的文档)请设置上面的LayoutManager
到 recyerview
CustomLayoutManagerlayoutManager = new CustomLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.smoothScrollToPosition(position);
通过使用自定义布局管理器
scrollToPosition
also working well in my case u can use
recyclerView.scrollToPosition(position)
此外,如果您想调整 smoothScrollToPosition 的速度,请覆盖
private static final float MILLISECONDS_PER_INCH = 50f;
在 CustomLayoutManager 中。
因此,如果我们将值设置为 1f smoothScrollToPosition 会更快,就像 scrollToPosition.increasing 值一样,延迟和减少将提高滚动速度。
希望这会有用。
尝试测量项目的宽度或高度并调用 smoothScrollBy(int dx, int dy)。
就我而言,
mRecyclerView.scrollToPosition(10);
也没有用。
但是
mRecyclerView.smoothScrollToPosition(10);
适合我...
如果您尝试快速滚动到 RecyclerView 顶部的某个位置,只需使用 LinearLayoutManager.scrollToPositionWithOffset 并将 0 作为偏移量。
示例:
mLinearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.scrollToPositionWithOffset(myPosition, 0);
smoothScrollToPosition 非常慢。如果你想要快速的东西,请使用 scrollToPositionWithOffset。
当您使用 scrollToPosition 时,它会显示在回收站视图的顶部。
但是如果你使用 smoothScrollToPosition 它会一直滚动到 Window 可见。这就是为什么当 smoothScrool 到下面的项目时,它会显示在底部
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(),currentPosition);
如何在设备旋转后执行平滑滚动并保存 RecyclerView
垂直位置:
这是适用于我的情况的方法,
public class MainFragment extends Fragment { //OR activity it's //fragment in my case
....
@Override
public void onLoadFinished(@NonNull Loader<List<Report>> loader, List<Report> objects) { // or other method of your choice, in my case it's a Loader
RecyclerView recyclerViewRv = findViewById(........;
.....
recyclerViewRv.setAdapter(.....Your adapter);
recyclerViewRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
recyclerScrollY = recyclerViewRv. computeVerticalScrollOffset();
}
});
//Apply smooth vertical scroll
recyclerViewRv.smoothScrollBy(0,recyclerScrollY);
}
//Save vertical scroll position before rotating devices
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("recyclerScrollY",recyclerScrollY);
}
//BackUp vertical scroll position after rotating devices
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
recyclerScrollY = savedInstanceState.getInt("recyclerScrollY");
}
}
//If you want to perform the same operation for horizontal scrolling just add a variable called recyclerScrollX = recyclerScrollY = recyclerViewRv. computeHorizontalScrollOffset(); then save in bundle
前面提到的任何解决方案可能不起作用的另一个原因是,如果您的 RecyclerView 嵌入到 NestedScrollView 中。在这种情况下,您必须在 NestedScrollView 上调用滚动操作。
例如:
nestedScrollview.smoothScrollTo(0,0)
实际上,如果您在 NestedScrollView 中有一个 RecyclerView,则每次您想要转到 RecyclerView 的开头时都必须使用这两行:
nestedScrollView.smoothScrollTo(0, 0);
layoutManager.scrollToPositionWithOffset(0, 0);
这完全适合我。
我遇到了一个奇怪的问题,其中 smoothScrollToPosition
只是偶尔工作。
After putting the smoothScrollToPosition inside Handler Post
Delayed with 1 second delay, it worked fine.
参考下面的Kotlin例子:
Handler().postDelayed({
recyclerViewObject.smoothScrollToPosition(0) // mention the position in place of 0
}, 1000) // 1000 indicates the 1 second delay.
这对我有用
Handler().postDelayed({
(recyclerView.getLayoutManager() as LinearLayoutManager).scrollToPositionWithOffset( 0, 0)
}, 100)
这个扩展非常有用,请试试。
fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
val smoothScroller = object : LinearSmoothScroller(this.context) {
override fun getVerticalSnapPreference(): Int = snapMode
override fun getHorizontalSnapPreference(): Int = snapMode
}
smoothScroller.targetPosition = position
layoutManager?.startSmoothScroll(smoothScroller)
}
所以我一直在寻找一种解决方案,以在另一个布局中使用 recyclerview 返回顶部,该布局顶部有一个视图(在我的例子中,我有一个带有 TextView 的 LinearLayout 和我的 recyclerview 内部)。因此,平滑滚动只会转到第一项的一半。
这是我所做的,效果非常好(Kotlin 解决方案):
back_to_top.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
GlobalScope.launch(Dispatchers.Main) {
recyclerview.layoutManager?.smoothScrollToPosition(recyclerview, RecyclerView.State(), 0)
delay((recyclerview.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() * 100L)
}.join()
recyclerview.scrollToPosition(0)
}
back_to_top.visibility = View.GONE
}
}
这里我做的是平滑滚动到第一个元素并将滚动延迟 100 毫秒乘以最后一个可见项,然后调用 scrollToPosition(0)(转到 top.correctly)
None 这些答案对我有用。我需要 smoothScrollToPosition
但@Ramz 的回答无效。我发现它会一直过度滚动,但只会朝一个方向滚动。我发现这似乎是物品装饰者把它扔掉了。我有一个水平布局,我想在除最后一项之外的每个项目之后添加一个 space,它不喜欢这种不对称。只要我在每个项目后面加上一个 space,它就起作用了!
我正在使用带有 GridLayoutManager 的基本 RecyclerView。我观察到 smoothScrollToPosition 和 scrollToPosition 都不能正常工作。
a) 当使用 smoothScrollToPosition
时,我经常收到来自 RecyclerView
"RecyclerView﹕ Passed over target position while smooth scrolling."
和 RecyclerView
没有正确滚动(通常会错过目标行)。这主要是在我试图滚动到某行的第一项时观察到的
b) 当使用 scrollToPosition
时,它似乎工作得很好,但大多数时候我只能看到该行的第一项,其余的没有显示。
你能给我一些提示,告诉我如何至少使其中一种方法正常工作吗?
非常感谢!
调用 recyclerView smoothScroll 无效,因为 recyclerView 本身不处理其布局。
您应该改为调用布局管理器滚动方法。
这应该看起来像这样
mRecyclerView.getLayoutManager().scrollToPosition(desiredPosition);
我终于成功了! LinearLayoutManager.scrollToPositionWithOffset(int, int)
成功了。
单击 EditText 时从 RecyclerView 中的任意位置平滑向下滚动到底部。
edittext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
rv_commentList.postDelayed(new Runnable() {
@Override
public void run() {
rv_commentList.scrollToPosition(rv_commentList.getAdapter().getItemCount() - 1);
}
}, 1000);
}
});
我也有同样的问题,但通过自定义 SmoothScroller 设法解决了这个问题
让 Custom LayoutManager 如下所示
public class CustomLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 50f;
private Context mContext;
public CustomLayoutManager(Context context) {
super(context);
mContext = context;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView,
RecyclerView.State state, final int position) {
LinearSmoothScroller smoothScroller =
new LinearSmoothScroller(mContext) {
//This controls the direction in which smoothScroll looks
//for your view
@Override
public PointF computeScrollVectorForPosition
(int targetPosition) {
return CustomLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
//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);
}
}
(上面给出的代码里面注释的文档)请设置上面的LayoutManager 到 recyerview
CustomLayoutManagerlayoutManager = new CustomLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.smoothScrollToPosition(position);
通过使用自定义布局管理器
scrollToPosition also working well in my case u can use
recyclerView.scrollToPosition(position)
此外,如果您想调整 smoothScrollToPosition 的速度,请覆盖
private static final float MILLISECONDS_PER_INCH = 50f;
在 CustomLayoutManager 中。 因此,如果我们将值设置为 1f smoothScrollToPosition 会更快,就像 scrollToPosition.increasing 值一样,延迟和减少将提高滚动速度。 希望这会有用。
尝试测量项目的宽度或高度并调用 smoothScrollBy(int dx, int dy)。
就我而言,
mRecyclerView.scrollToPosition(10);
也没有用。 但是
mRecyclerView.smoothScrollToPosition(10);
适合我...
如果您尝试快速滚动到 RecyclerView 顶部的某个位置,只需使用 LinearLayoutManager.scrollToPositionWithOffset 并将 0 作为偏移量。
示例:
mLinearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.scrollToPositionWithOffset(myPosition, 0);
smoothScrollToPosition 非常慢。如果你想要快速的东西,请使用 scrollToPositionWithOffset。
当您使用 scrollToPosition 时,它会显示在回收站视图的顶部。
但是如果你使用 smoothScrollToPosition 它会一直滚动到 Window 可见。这就是为什么当 smoothScrool 到下面的项目时,它会显示在底部
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(),currentPosition);
如何在设备旋转后执行平滑滚动并保存 RecyclerView
垂直位置:
这是适用于我的情况的方法,
public class MainFragment extends Fragment { //OR activity it's //fragment in my case
....
@Override
public void onLoadFinished(@NonNull Loader<List<Report>> loader, List<Report> objects) { // or other method of your choice, in my case it's a Loader
RecyclerView recyclerViewRv = findViewById(........;
.....
recyclerViewRv.setAdapter(.....Your adapter);
recyclerViewRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
recyclerScrollY = recyclerViewRv. computeVerticalScrollOffset();
}
});
//Apply smooth vertical scroll
recyclerViewRv.smoothScrollBy(0,recyclerScrollY);
}
//Save vertical scroll position before rotating devices
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("recyclerScrollY",recyclerScrollY);
}
//BackUp vertical scroll position after rotating devices
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
recyclerScrollY = savedInstanceState.getInt("recyclerScrollY");
}
}
//If you want to perform the same operation for horizontal scrolling just add a variable called recyclerScrollX = recyclerScrollY = recyclerViewRv. computeHorizontalScrollOffset(); then save in bundle
前面提到的任何解决方案可能不起作用的另一个原因是,如果您的 RecyclerView 嵌入到 NestedScrollView 中。在这种情况下,您必须在 NestedScrollView 上调用滚动操作。
例如:
nestedScrollview.smoothScrollTo(0,0)
实际上,如果您在 NestedScrollView 中有一个 RecyclerView,则每次您想要转到 RecyclerView 的开头时都必须使用这两行:
nestedScrollView.smoothScrollTo(0, 0);
layoutManager.scrollToPositionWithOffset(0, 0);
这完全适合我。
我遇到了一个奇怪的问题,其中 smoothScrollToPosition
只是偶尔工作。
After putting the smoothScrollToPosition inside Handler Post Delayed with 1 second delay, it worked fine.
参考下面的Kotlin例子:
Handler().postDelayed({
recyclerViewObject.smoothScrollToPosition(0) // mention the position in place of 0
}, 1000) // 1000 indicates the 1 second delay.
这对我有用
Handler().postDelayed({
(recyclerView.getLayoutManager() as LinearLayoutManager).scrollToPositionWithOffset( 0, 0)
}, 100)
这个扩展非常有用,请试试。
fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
val smoothScroller = object : LinearSmoothScroller(this.context) {
override fun getVerticalSnapPreference(): Int = snapMode
override fun getHorizontalSnapPreference(): Int = snapMode
}
smoothScroller.targetPosition = position
layoutManager?.startSmoothScroll(smoothScroller)
}
所以我一直在寻找一种解决方案,以在另一个布局中使用 recyclerview 返回顶部,该布局顶部有一个视图(在我的例子中,我有一个带有 TextView 的 LinearLayout 和我的 recyclerview 内部)。因此,平滑滚动只会转到第一项的一半。
这是我所做的,效果非常好(Kotlin 解决方案):
back_to_top.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
GlobalScope.launch(Dispatchers.Main) {
recyclerview.layoutManager?.smoothScrollToPosition(recyclerview, RecyclerView.State(), 0)
delay((recyclerview.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() * 100L)
}.join()
recyclerview.scrollToPosition(0)
}
back_to_top.visibility = View.GONE
}
}
这里我做的是平滑滚动到第一个元素并将滚动延迟 100 毫秒乘以最后一个可见项,然后调用 scrollToPosition(0)(转到 top.correctly)
None 这些答案对我有用。我需要 smoothScrollToPosition
但@Ramz 的回答无效。我发现它会一直过度滚动,但只会朝一个方向滚动。我发现这似乎是物品装饰者把它扔掉了。我有一个水平布局,我想在除最后一项之外的每个项目之后添加一个 space,它不喜欢这种不对称。只要我在每个项目后面加上一个 space,它就起作用了!