如何禁用 RecyclerView 滚动?
How to disable RecyclerView scrolling?
我无法在 RecyclerView
中禁用滚动。我尝试调用 rv.setEnabled(false)
但我仍然可以滚动。
如何禁用滚动?
这个解决方法有点老套,但它确实有效;您可以 enable/disable 在 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) {
}
}
使用它:
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
扩展 LayoutManager
并覆盖 canScrollHorizontally()
和 canScrollVertically()
以禁用滚动。
请注意,在开头插入项目不会自动滚动回开头,要解决此问题,请执行以下操作:
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);
}
}
}
});
}
另一种选择是 setLayoutFrozen
,但它有很多其他副作用。
这对我有用:
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
出于某种原因,@Alejandro Gracia 的回答仅在几秒钟后才开始工作。
我找到了一个立即阻止 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) {
}
});
我知道这已经有一个可接受的答案,但该解决方案没有考虑到我遇到的 use-case。
我特别需要一个 header 项目,它仍然可以点击,但禁用了 RecyclerView 的滚动机制。这可以通过以下代码完成:
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) {
}
});
为此,您应该覆盖 recycleView
的 layoutManager
。这样它只会禁用滚动,none 其他功能。您仍然可以处理点击或任何其他触摸事件。例如:-
原文:
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();
}
}
在这里使用“isScrollEnabled”标志,您可以enable/disable临时回收视图的滚动功能。
还有:
简单地覆盖您现有的实现以禁用滚动并允许点击。
linearLayoutManager = new LinearLayoutManager(context) {
@Override
public boolean canScrollVertically() {
return false;
}
};
在 Kotlin 中:
object : LinearLayoutManager(this){ override fun canScrollVertically(): Boolean { return false } }
真正的答案是
recyclerView.setNestedScrollingEnabled(false);
更多信息见documentation
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// Stop only scrolling.
return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
}
});
覆盖 onTouchEvent() 和 onInterceptTouchEvent() 并且 return 如果您根本不需要 OnItemTouchListener,则为 false。
这不会禁用 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;
}
}
我已经在这个问题上苦苦挣扎了几个小时,
所以我想分享我的经验,
对于 layoutManager 解决方案,它很好,但如果你想重新启用滚动,回收器将回到顶部。
到目前为止(至少对我而言)最好的解决方案是使用@Zsolt Safrany 方法但添加 getter 和 setter 这样您就不必删除或添加 OnItemTouchListener。
如下
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){}
}
用法
RecyclerViewDisabler disabler = new RecyclerViewDisabler(true);
feedsRecycler.addOnItemTouchListener(disabler);
// TO ENABLE/DISABLE JUST USE THIS
disabler.setEnable(enable);
创建 class 扩展 RecyclerView class
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();
}
}
这将禁用滚动事件,但不会禁用点击事件
在您的 XML 中使用它执行以下操作:
<com.yourpackage.xyx.NonScrollRecyclerView
...
...
/>
真实真实的答案是:
API 21 岁及以上:
不需要 java 代码。
您可以设置 android:nestedScrollingEnabled="false"
在 xml:
<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">
这是我使用数据绑定的方式:
<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}"/>
代替 "true" 我使用了一个布尔变量,该变量根据条件进行更改,以便回收器视图在禁用和启用之间切换。
写了一个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
}
用法:
recyclerView.layoutManager = NoScrollLinearLayoutManager(context)
(recyclerView.layoutManager as NoScrollLinearLayoutManager).disableScrolling()
遇到一个包含多个 RecycleView 的片段,所以我只需要一个滚动条而不是每个 RecycleView 中的一个滚动条。
所以我只是将 ScrollView 放在包含 2 个 RecycleView 的父容器中,并在 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" />
只需将此添加到 xml
中的回收视图
android:nestedScrollingEnabled="false"
像这样
<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">
在XML中:-
您可以添加
android:nestedScrollingEnabled="false"
在子 RecyclerView 布局中 XML 文件
或
在Java :-
childRecyclerView.setNestedScrollingEnabled(false);
在 Java 代码中添加到您的 RecyclerView。
使用 ViewCompat (Java) :-
childRecyclerView.setNestedScrollingEnabled(false);
仅适用于 android_version>21 设备。要在所有设备上工作,请使用以下内容
ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);
添加
android:descendantFocusability="blocksDescendants"
在您的 SrollView 或 NestedScrollView 的子级(以及 ListView、recyclerview 和 gridview 的任何一个的父级)中
如果您只是禁用RecyclerView
的仅滚动功能,那么您可以使用RecyclerView
的setLayoutFrozen(true);
方法。但是不能禁用触摸事件。
your_recyclerView.setLayoutFrozen(true);
有一种更直接的方法来禁用滚动(从技术上讲,它更像是拦截滚动事件并在满足条件时结束它),仅使用标准功能。 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();
}
}
});
用例:
假设您想在单击 RecyclerView
中的某个项目时禁用滚动,这样您就可以使用它执行一些操作,而不会因不小心滚动到另一个项目而分心,当您完成它时,只需再次单击该项目以启用滚动。为此,您可能希望将 OnClickListener
附加到 RecyclerView
中的每个项目,因此当您单击一个项目时,它会将 isItemSelected
从 false
切换到 true
.这样,当您尝试滚动时,RecyclerView
将自动调用方法 onScrollStateChanged
,并且由于 isItemSelected
设置为 true
,它将在 RecyclerView
获得机会,嗯...滚动。
注意:为了更好的可用性,请尝试使用 GestureListener
而不是 OnClickListener
以防止 accidental
次点击。
您可以通过冻结 RecyclerView 来禁用滚动。
冻结:
recyclerView.setLayoutFrozen(true)
解冻:recyclerView.setLayoutFrozen(false)
您可以在设置适配器后添加此行
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
现在你的 recyclerview 可以平滑滚动了
答案非常简单。
LinearLayoutManager lm = new LinearLayoutManager(getContext()) {
@Override
public boolean canScrollVertically() {
return false;
}
};
以上代码禁用 RecyclerView 垂直滚动。
由于 setLayoutFrozen
已弃用,您可以通过使用 suppressLayout
.
冻结 RecyclerView 来禁用滚动
冻结:
recyclerView.suppressLayout(true)
解冻:
recyclerView.suppressLayout(false)
停止通过触摸滚动,但通过命令继续滚动:
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;
}
});
}
在 Kotlin 中,如果您不想创建额外的 class 只是为了设置一个值,您可以从 LayoutManager 创建匿名 class:
recyclerView.layoutManager = object : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean = false
}
您应该只添加这一行:
recyclerView.suppressLayout(true)
对于那些只想阻止用户滚动 RecyclerView 而没有松动 smoothScrollToPosition
或任何其他“定位”方法的人,我建议扩展 RecyclerView
class, 覆盖
onTouchEvent
。像这样:
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;
}
}
在activity的onCreate方法中,你可以简单地做:
recyclerView.stopScroll()
它停止滚动。
您可以创建扩展 Recycler View class 的 Non Scrollable Recyclerview,如下所示:
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();
}
}
2022 年 5 月
在新版本的 android 和 API 中进行了大量尝试后,这种方法对我很有效。
Kotlin 的新答案
- 创建一个名为
ScrollDisabledRecyclerView
的 class
并输入如下代码:
class 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
} }
- 在你的 XML 中使用这个 class 而不是 RecyclerView(这个 class 是从它扩展的):
<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" />
- 最后,使用[=15]中的按钮处理下一个和上一个 =] 像这样:
注意:我正在使用 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
)
}
}
我无法在 RecyclerView
中禁用滚动。我尝试调用 rv.setEnabled(false)
但我仍然可以滚动。
如何禁用滚动?
这个解决方法有点老套,但它确实有效;您可以 enable/disable 在 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) {
}
}
使用它:
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
扩展 LayoutManager
并覆盖 canScrollHorizontally()
和 canScrollVertically()
以禁用滚动。
请注意,在开头插入项目不会自动滚动回开头,要解决此问题,请执行以下操作:
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);
}
}
}
});
}
另一种选择是 setLayoutFrozen
,但它有很多其他副作用。
这对我有用:
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
出于某种原因,@Alejandro Gracia 的回答仅在几秒钟后才开始工作。
我找到了一个立即阻止 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) {
}
});
我知道这已经有一个可接受的答案,但该解决方案没有考虑到我遇到的 use-case。
我特别需要一个 header 项目,它仍然可以点击,但禁用了 RecyclerView 的滚动机制。这可以通过以下代码完成:
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) {
}
});
为此,您应该覆盖 recycleView
的 layoutManager
。这样它只会禁用滚动,none 其他功能。您仍然可以处理点击或任何其他触摸事件。例如:-
原文:
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();
}
}
在这里使用“isScrollEnabled”标志,您可以enable/disable临时回收视图的滚动功能。
还有:
简单地覆盖您现有的实现以禁用滚动并允许点击。
linearLayoutManager = new LinearLayoutManager(context) {
@Override
public boolean canScrollVertically() {
return false;
}
};
在 Kotlin 中:
object : LinearLayoutManager(this){ override fun canScrollVertically(): Boolean { return false } }
真正的答案是
recyclerView.setNestedScrollingEnabled(false);
更多信息见documentation
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// Stop only scrolling.
return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
}
});
覆盖 onTouchEvent() 和 onInterceptTouchEvent() 并且 return 如果您根本不需要 OnItemTouchListener,则为 false。 这不会禁用 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;
}
}
我已经在这个问题上苦苦挣扎了几个小时, 所以我想分享我的经验, 对于 layoutManager 解决方案,它很好,但如果你想重新启用滚动,回收器将回到顶部。
到目前为止(至少对我而言)最好的解决方案是使用@Zsolt Safrany 方法但添加 getter 和 setter 这样您就不必删除或添加 OnItemTouchListener。
如下
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){}
}
用法
RecyclerViewDisabler disabler = new RecyclerViewDisabler(true);
feedsRecycler.addOnItemTouchListener(disabler);
// TO ENABLE/DISABLE JUST USE THIS
disabler.setEnable(enable);
创建 class 扩展 RecyclerView class
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();
}
}
这将禁用滚动事件,但不会禁用点击事件
在您的 XML 中使用它执行以下操作:
<com.yourpackage.xyx.NonScrollRecyclerView
...
...
/>
真实真实的答案是: API 21 岁及以上:
不需要 java 代码。
您可以设置 android:nestedScrollingEnabled="false"
在 xml:
<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">
这是我使用数据绑定的方式:
<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}"/>
代替 "true" 我使用了一个布尔变量,该变量根据条件进行更改,以便回收器视图在禁用和启用之间切换。
写了一个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
}
用法:
recyclerView.layoutManager = NoScrollLinearLayoutManager(context)
(recyclerView.layoutManager as NoScrollLinearLayoutManager).disableScrolling()
遇到一个包含多个 RecycleView 的片段,所以我只需要一个滚动条而不是每个 RecycleView 中的一个滚动条。
所以我只是将 ScrollView 放在包含 2 个 RecycleView 的父容器中,并在 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" />
只需将此添加到 xml
中的回收视图 android:nestedScrollingEnabled="false"
像这样
<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">
在XML中:-
您可以添加
android:nestedScrollingEnabled="false"
在子 RecyclerView 布局中 XML 文件
或
在Java :-
childRecyclerView.setNestedScrollingEnabled(false);
在 Java 代码中添加到您的 RecyclerView。
使用 ViewCompat (Java) :-
childRecyclerView.setNestedScrollingEnabled(false);
仅适用于 android_version>21 设备。要在所有设备上工作,请使用以下内容
ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);
添加
android:descendantFocusability="blocksDescendants"
在您的 SrollView 或 NestedScrollView 的子级(以及 ListView、recyclerview 和 gridview 的任何一个的父级)中
如果您只是禁用RecyclerView
的仅滚动功能,那么您可以使用RecyclerView
的setLayoutFrozen(true);
方法。但是不能禁用触摸事件。
your_recyclerView.setLayoutFrozen(true);
有一种更直接的方法来禁用滚动(从技术上讲,它更像是拦截滚动事件并在满足条件时结束它),仅使用标准功能。 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();
}
}
});
用例:
假设您想在单击 RecyclerView
中的某个项目时禁用滚动,这样您就可以使用它执行一些操作,而不会因不小心滚动到另一个项目而分心,当您完成它时,只需再次单击该项目以启用滚动。为此,您可能希望将 OnClickListener
附加到 RecyclerView
中的每个项目,因此当您单击一个项目时,它会将 isItemSelected
从 false
切换到 true
.这样,当您尝试滚动时,RecyclerView
将自动调用方法 onScrollStateChanged
,并且由于 isItemSelected
设置为 true
,它将在 RecyclerView
获得机会,嗯...滚动。
注意:为了更好的可用性,请尝试使用 GestureListener
而不是 OnClickListener
以防止 accidental
次点击。
您可以通过冻结 RecyclerView 来禁用滚动。
冻结:
recyclerView.setLayoutFrozen(true)
解冻:recyclerView.setLayoutFrozen(false)
您可以在设置适配器后添加此行
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
现在你的 recyclerview 可以平滑滚动了
答案非常简单。
LinearLayoutManager lm = new LinearLayoutManager(getContext()) {
@Override
public boolean canScrollVertically() {
return false;
}
};
以上代码禁用 RecyclerView 垂直滚动。
由于 setLayoutFrozen
已弃用,您可以通过使用 suppressLayout
.
冻结:
recyclerView.suppressLayout(true)
解冻:
recyclerView.suppressLayout(false)
停止通过触摸滚动,但通过命令继续滚动:
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;
}
});
}
在 Kotlin 中,如果您不想创建额外的 class 只是为了设置一个值,您可以从 LayoutManager 创建匿名 class:
recyclerView.layoutManager = object : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean = false
}
您应该只添加这一行:
recyclerView.suppressLayout(true)
对于那些只想阻止用户滚动 RecyclerView 而没有松动 smoothScrollToPosition
或任何其他“定位”方法的人,我建议扩展 RecyclerView
class, 覆盖
onTouchEvent
。像这样:
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;
}
}
在activity的onCreate方法中,你可以简单地做:
recyclerView.stopScroll()
它停止滚动。
您可以创建扩展 Recycler View class 的 Non Scrollable Recyclerview,如下所示:
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();
}
}
2022 年 5 月
在新版本的 android 和 API 中进行了大量尝试后,这种方法对我很有效。
Kotlin 的新答案
- 创建一个名为
ScrollDisabledRecyclerView
的class
并输入如下代码:
class 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 } }
- 在你的 XML 中使用这个 class 而不是 RecyclerView(这个 class 是从它扩展的):
<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" />
- 最后,使用[=15]中的按钮处理下一个和上一个 =] 像这样:
注意:我正在使用 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
)
}
}