[英]How to disable RecyclerView scrolling?
I cannot disable scrolling in the RecyclerView
.我无法在
RecyclerView
中禁用滚动。 I tried calling rv.setEnabled(false)
but I can still scroll.我尝试调用
rv.setEnabled(false)
但我仍然可以滚动。
How can I disable scrolling?如何禁用滚动?
You should override the layoutManager
of your recycleView
for this.为此,您应该覆盖
recycleView
的layoutManager
。 This way it will only disable scrolling, none of the other functionalities.这样它只会禁用滚动,没有其他功能。 You will still be able to handle click or any other touch events.
您仍然可以处理点击或任何其他触摸事件。 For example:-
例如:-
Original:原来的:
public class CustomGridLayoutManager extends LinearLayoutManager {
private boolean isScrollEnabled = true;
public CustomGridLayoutManager(Context context) {
super(context);
}
public void setScrollEnabled(boolean flag) {
this.isScrollEnabled = flag;
}
@Override
public boolean canScrollVertically() {
//Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
return isScrollEnabled && super.canScrollVertically();
}
}
Here using "isScrollEnabled" flag you can enable/disable scrolling functionality of your recycle-view temporarily.在这里使用“isScrollEnabled”标志,您可以临时启用/禁用回收视图的滚动功能。
Also:还:
Simple override your existing implementation to disable scrolling and allow clicking.简单地覆盖您现有的实现以禁用滚动并允许单击。
linearLayoutManager = new LinearLayoutManager(context) {
@Override
public boolean canScrollVertically() {
return false;
}
};
In Kotlin:在科特林:
object : LinearLayoutManager(this){ override fun canScrollVertically(): Boolean { return false } }
The real answer is真正的答案是
recyclerView.setNestedScrollingEnabled(false);
More info in documentation 文档中的更多信息
The REAL REAL answer is: For API 21 and above:真正的真正答案是:对于 API 21 及更高版本:
No java code needed.不需要java代码。 You can set
android:nestedScrollingEnabled="false"
in xml:您可以在 xml 中设置
android:nestedScrollingEnabled="false"
:
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="true"
android:nestedScrollingEnabled="false"
tools:listitem="@layout/adapter_favorite_place">
This a bit hackish workaround but it works;这有点骇人听闻的解决方法,但它有效; you can enable/disable scrolling in the
RecyclerView
.您可以在
RecyclerView
中启用/禁用滚动。
This is an empty RecyclerView.OnItemTouchListener
stealing every touch event thus disabling the target RecyclerView
.这是一个空的
RecyclerView.OnItemTouchListener
窃取每个触摸事件,从而禁用目标RecyclerView
。
public class RecyclerViewDisabler implements RecyclerView.OnItemTouchListener {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return true;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
Using it:使用它:
RecyclerView rv = ...
RecyclerView.OnItemTouchListener disabler = new RecyclerViewDisabler();
rv.addOnItemTouchListener(disabler); // disables scolling
// do stuff while scrolling is disabled
rv.removeOnItemTouchListener(disabler); // scrolling is enabled again
This works for me:这对我有用:
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
As setLayoutFrozen
is deprecated, You can disable scrolling by freezing your RecyclerView by using suppressLayout
.由于不推荐使用
setLayoutFrozen
,您可以通过使用suppressLayout
冻结 RecyclerView 来禁用滚动。
To freeze:冻结:
recyclerView.suppressLayout(true)
To unfreeze:解冻:
recyclerView.suppressLayout(false)
You can disable scrolling by freezing your RecyclerView.您可以通过冻结 RecyclerView 来禁用滚动。
To freeze: recyclerView.setLayoutFrozen(true)
冻结:
recyclerView.setLayoutFrozen(true)
To unfreeze: recyclerView.setLayoutFrozen(false)
解冻:
recyclerView.setLayoutFrozen(false)
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// Stop only scrolling.
return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
}
});
Create class which extend RecyclerView class创建扩展RecyclerView类的类
public class NonScrollRecyclerView extends RecyclerView {
public NonScrollRecyclerView(Context context) {
super(context);
}
public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
This will disable the scroll event, but not the click events这将禁用滚动事件,但不会禁用点击事件
Use this in your XML do the following:在您的 XML 中使用它执行以下操作:
<com.yourpackage.xyx.NonScrollRecyclerView
...
...
/>
If you just disable only scroll functionality of RecyclerView
then you can use setLayoutFrozen(true);
如果您只禁用
RecyclerView
的滚动功能,那么您可以使用setLayoutFrozen(true);
method of RecyclerView
. RecyclerView
的方法。 But it can not be disable touch event.但它不能禁用触摸事件。
your_recyclerView.setLayoutFrozen(true);
There is a simple answer.有一个简单的答案。
LinearLayoutManager lm = new LinearLayoutManager(getContext()) {
@Override
public boolean canScrollVertically() {
return false;
}
};
The above code disables RecyclerView's verticall scrolling.上面的代码禁用了 RecyclerView 的垂直滚动。
Wrote a kotlin version:写了一个kotlin版本:
class NoScrollLinearLayoutManager(context: Context?) : LinearLayoutManager(context) {
private var scrollable = true
fun enableScrolling() {
scrollable = true
}
fun disableScrolling() {
scrollable = false
}
override fun canScrollVertically() =
super.canScrollVertically() && scrollable
override fun canScrollHorizontally() =
super.canScrollVertically()
&& scrollable
}
usage:用法:
recyclerView.layoutManager = NoScrollLinearLayoutManager(context)
(recyclerView.layoutManager as NoScrollLinearLayoutManager).disableScrolling()
In Kotlin, if you don't want to create an extra class just for setting one value, you can create anonymous class from LayoutManager:在 Kotlin 中,如果您不想为了设置一个值而创建一个额外的类,您可以从 LayoutManager 创建匿名类:
recyclerView.layoutManager = object : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean = false
}
in XML :-在 XML 中:-
You can add你可以加
android:nestedScrollingEnabled="false"
in the child RecyclerView layout XML file在子 RecyclerView 布局 XML 文件中
or或者
in Java :-在 Java 中:-
childRecyclerView.setNestedScrollingEnabled(false);
to your RecyclerView in Java code. Java 代码中的 RecyclerView。
Using ViewCompat (Java) :-使用 ViewCompat (Java):-
childRecyclerView.setNestedScrollingEnabled(false);
will work only in android_version>21 devices.仅适用于android_version>21设备。 to work in all devices use the following
在所有设备上工作使用以下
ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);
Another alternative is setLayoutFrozen
, but it comes with a bunch of other side effects.另一种选择是
setLayoutFrozen
,但它带有许多其他副作用。
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setLayoutFrozen(boolean) https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setLayoutFrozen(boolean)
Extend the LayoutManager
and override canScrollHorizontally()
and canScrollVertically()
to disable scrolling.扩展
LayoutManager
并覆盖canScrollHorizontally()
和canScrollVertically()
以禁用滚动。
Be aware that inserting items at the beginning will not automatically scroll back to the beginning, to get around this do something like:请注意,在开头插入项目不会自动滚动回到开头,要解决这个问题,请执行以下操作:
private void clampRecyclerViewScroll(final RecyclerView recyclerView)
{
recyclerView.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver()
{
@Override
public void onItemRangeInserted(int positionStart, int itemCount)
{
super.onItemRangeInserted(positionStart, itemCount);
// maintain scroll position at top
if (positionStart == 0)
{
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
((GridLayoutManager) layoutManager).scrollToPositionWithOffset(0, 0);
}else if(layoutManager instanceof LinearLayoutManager)
{
((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(0, 0);
}
}
}
});
}
I know this already has an accepted answer, but the solution doesn't take into account a use-case that I came across.我知道这已经有一个可接受的答案,但该解决方案没有考虑到我遇到的用例。
I specifically needed a header item that was still clickable, yet disabled the scrolling mechanism of the RecyclerView.我特别需要一个仍然可以点击的标题项,但禁用了 RecyclerView 的滚动机制。 This can be accomplished with the following code:
这可以通过以下代码来完成:
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return e.getAction() == MotionEvent.ACTION_MOVE;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
你应该只添加这一行:
recyclerView.suppressLayout(true)
For some reason @Alejandro Gracia answer starts working only after a few second.出于某种原因,@Alejandro Gracia 答案仅在几秒钟后才开始工作。 I found a solution that blocks the RecyclerView instantaneously:
我找到了一个立即阻止 RecyclerView 的解决方案:
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return true;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
Override onTouchEvent() and onInterceptTouchEvent() and return false if you don't need OnItemTouchListener at all.如果您根本不需要 OnItemTouchListener,则覆盖 onTouchEvent() 和 onInterceptTouchEvent() 并返回 false。 This does not disable OnClickListeners of ViewHolders.
这不会禁用 ViewHolders 的 OnClickListeners。
public class ScrollDisabledRecyclerView extends RecyclerView {
public ScrollDisabledRecyclerView(Context context) {
super(context);
}
public ScrollDisabledRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ScrollDisabledRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return false;
}
}
Just add this to your recycleview in xml只需将其添加到 xml 中的回收视图
android:nestedScrollingEnabled="false"
like this像这样
<android.support.v7.widget.RecyclerView
android:background="#ffffff"
android:id="@+id/myrecycle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false">
Add添加
android:descendantFocusability="blocksDescendants"
in your child of SrollView or NestedScrollView (and parent of ListView, recyclerview and gridview any one)在您的 SrollView 或 NestedScrollView 的子级(以及 ListView、recyclerview 和 gridview 的父级中的任何一个)
At activity's onCreate method, you can simply do:在活动的 onCreate 方法中,您可以简单地执行以下操作:
recyclerView.stopScroll()
and it stops scrolling.它停止滚动。
I have been struggling in this issue for some hour, So I would like to share my experience, For the layoutManager solution it is fine but if u want to reEnable scrolling the recycler will back to top.我已经在这个问题上苦苦挣扎了几个小时,所以我想分享我的经验,对于 layoutManager 解决方案很好,但如果你想重新启用滚动,回收器将回到顶部。
The best solution so far (for me at least) is using @Zsolt Safrany methode but adding getter and setter so you don't have to remove or add the OnItemTouchListener.到目前为止(至少对我而言)最好的解决方案是使用 @Zsolt Safrany 方法,但添加 getter 和 setter,这样您就不必删除或添加 OnItemTouchListener。
As follow如下
public class RecyclerViewDisabler implements RecyclerView.OnItemTouchListener {
boolean isEnable = true;
public RecyclerViewDisabler(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
public void setEnable(boolean enable) {
isEnable = enable;
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return !isEnable;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept){}
}
Usage用法
RecyclerViewDisabler disabler = new RecyclerViewDisabler(true);
feedsRecycler.addOnItemTouchListener(disabler);
// TO ENABLE/DISABLE JUST USE THIS
disabler.setEnable(enable);
There is a more straightforward way to disable scrolling (technically it is more rather interception of a scrolling event and ending it when a condition is met), using just standard functionality.有一种更直接的方法来禁用滚动(从技术上讲,它更像是拦截滚动事件并在满足条件时结束它),仅使用标准功能。
RecyclerView
has the method called addOnScrollListener(OnScrollListener listener)
, and using just this you can stop it from scrolling, just so: RecyclerView
有一个叫做addOnScrollListener(OnScrollListener listener)
的方法,使用这个你可以阻止它滚动,就像这样:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (viewModel.isItemSelected) {
recyclerView.stopScroll();
}
}
});
Use case: Let's say that you want to disable scrolling when you click on one of the items within RecyclerView
so you could perform some actions with it, without being distracted by accidentally scrolling to another item, and when you are done with it, just click on the item again to enable scrolling.用例:假设您希望在单击
RecyclerView
中的一个项目时禁用滚动,这样您就可以使用它执行一些操作,而不会因意外滚动到另一个项目而分心,当您完成它时,只需单击再次在项目上启用滚动。 For that, you would want to attach OnClickListener
to every item within RecyclerView
, so when you click on an item, it would toggle isItemSelected
from false
to true
.为此,您需要将
OnClickListener
附加到RecyclerView
中的每个项目,因此当您单击一个项目时,它会将isItemSelected
从false
切换为true
。 This way when you try to scroll, RecyclerView
will automatically call method onScrollStateChanged
and since isItemSelected
set to true
, it will stop immediately, before RecyclerView
got the chance, well... to scroll.这样,当您尝试滚动时,
RecyclerView
将自动调用方法onScrollStateChanged
,并且由于isItemSelected
设置为true
,它会立即停止,在RecyclerView
有机会之前...滚动。
Note: for better usability, try to use GestureListener
instead of OnClickListener
to prevent accidental
clicks.注意:为了更好的可用性,尽量使用
GestureListener
而不是OnClickListener
来防止accidental
点击。
You can add this line after setting your adapter您可以在设置适配器后添加此行
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
Now your recyclerview will work with smooth scrolling现在你的 recyclerview 将与平滑滚动一起工作
For whom want's to just prevent the user to scroll the RecyclerView, without loose the smoothScrollToPosition
or any other "go to position" method, I'd recommend rather extending the RecyclerView
class, overriding the onTouchEvent
.对于只想阻止用户滚动 RecyclerView 而不松动
smoothScrollToPosition
或任何其他“定位”方法的人,我建议宁愿扩展RecyclerView
类,覆盖onTouchEvent
。 Like this:像这样:
public class HardwareButtonsRecyclerView extends RecyclerView {
public HardwareButtonsRecyclerView(@NonNull Context context) {
super(context);
}
public HardwareButtonsRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public HardwareButtonsRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
return false;
}
}
Here is how I did it with data binding:以下是我使用数据绑定的方法:
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:onTouch="@{(v,e) -> true}"/>
In place of the "true" I used a boolean variable that changed based on a condition so that the recycler view would switch between being disabled and enabled.代替“true”,我使用了一个根据条件更改的布尔变量,以便回收器视图将在禁用和启用之间切换。
For stop scrolling by touch but keep scrolling via commands :对于通过触摸停止滚动但通过命令继续滚动:
if (appTopBarMessagesRV == null) { appTopBarMessagesRV = findViewById(R.id.mainBarScrollMessagesRV); if (appTopBarMessagesRV == null) { appTopBarMessagesRV = findViewById(R.id.mainBarScrollMessagesRV);
appTopBarMessagesRV.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if ( rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING)
{
// Stop scrolling by touch
return false;
}
return true;
}
});
}
You can creat a Non Scrollable Recycler View which extends a Recycler View class, as follows:您可以创建一个扩展 Recycler View 类的 Non Scrollable Recycler View,如下所示:
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
public class NonScrollRecyclerView extends RecyclerView {
public NonScrollRecyclerView(Context context) {
super(context);
}
public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasure, int heightMeasure) {
int heightMeasureCustom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasure, heightMeasureCustom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
Came across with a fragment that contains multiple RecycleView so I only need one scrollbar instead of one scrollbar in each RecycleView.遇到一个包含多个 RecycleView 的片段,所以我只需要一个滚动条而不是每个 RecycleView 中的一个滚动条。
So I just put the ScrollView in the parent container that contains the 2 RecycleViews and use android:isScrollContainer="false"
in the RecycleView所以我只是将 ScrollView 放在包含 2 个 RecycleViews 的父容器中,并在 RecycleView 中使用
android:isScrollContainer="false"
<android.support.v7.widget.RecyclerView 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"
app:layoutManager="LinearLayoutManager"
android:isScrollContainer="false" />
MAY 2022 2022 年 5 月
This way worked for me after a lot of tries in new versions of android and APIs.在对新版本的 android 和 API 进行了大量尝试后,这种方式对我有用。
The New Answer With Kotlin Kotlin 的新答案
class
called ScrollDisabledRecyclerView
and put codes like this:ScrollDisabledRecyclerView
的class
并放置如下代码:class ScrollDisabledRecyclerView : RecyclerView {
类 ScrollDisabledRecyclerView : RecyclerView {
constructor(context: Context?) : super(context!!) constructor(context: Context?, @Nullable attrs: AttributeSet?) : super(context!!, attrs) constructor(context: Context?, @Nullable attrs: AttributeSet?, defStyle: Int) : super( context!!, attrs, defStyle ) override fun onTouchEvent(e: MotionEvent): Boolean { return e.action == MotionEvent.ACTION_MOVE } override fun onInterceptTouchEvent(e: MotionEvent): Boolean { return false } }
<info.sanaebadi.ScrollDisabledRecyclerView android:id="@+id/recyclerView" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginBottom="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" android:clipToPadding="true" tools:listitem="@layout/multiple_questions_row" />
MainActiviy
like this:MainActiviy
中的按钮处理下一个和上一个,如下所示: note: I AM USING ViewBinding
注意:我正在使用
ViewBinding
binding.buttonNextQuestion.setOnClickListener {
val totalItemCount: Int = binding.recyclerView.adapter!!.itemCount
if (totalItemCount <= 0) return@setOnClickListener
val lastVisibleItemIndex: Int = linearLayoutManager.findLastVisibleItemPosition()
if (lastVisibleItemIndex >= totalItemCount) return@setOnClickListener
linearLayoutManager.smoothScrollToPosition(
binding.recyclerView,
null,
lastVisibleItemIndex + 1
)
}
binding.buttonPreviousQuestion.setOnClickListener {
val firstVisibleItemIndex: Int =
linearLayoutManager.findFirstCompletelyVisibleItemPosition()
if (firstVisibleItemIndex > 0) {
linearLayoutManager.smoothScrollToPosition(
binding.recyclerView,
null,
firstVisibleItemIndex - 1
)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.