如何禁用RecyclerView滚动?

我无法禁用RecyclerView滚动。 我试着调用rv.setEnabled(false)但我仍然可以滚动。

我怎样才能禁用滚动?

你应该重写你的recycleview的layoutmanager。 这样只会禁用滚动function,而没有其他function。 您仍然可以处理点击或任何其他触摸事件。 例如:-

原版的:

  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”标志,您可以暂时启用/禁用回收视图的滚动function。

也:

简单覆盖您的现有实施禁用滚动,并允许点击。

  linearLayoutManager = new LinearLayoutManager(context) { @Override public boolean canScrollVertically() { return false; } }; 

真正的答案是

 recyclerView.setNestedScrollingEnabled(false); 

更多信息在文档中

这有点hackish解决方法,但它的工作原理; 您可以启用/禁用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 

这适用于我:

  recyclerView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return true; } }); 

扩展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); } } } }); } 

另一个select是setLayoutFrozen ,但它带有一堆其他的副作用。

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setLayoutFrozen(boolean);

你也可以在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"> 

我知道这已经有了一个可以接受的答案,但是这个解决scheme没有考虑到我遇到的一个用例。

我特别需要一个仍然可点击的标题项目,但禁用了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) { } }); 
 recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { // Stop only scrolling. return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING; } }); 

出于某种原因@Alejandro Gracia答案只有在几秒钟后才开始工作。 我发现了一个即时阻止RecyclerView的解决scheme:

 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) { } }); 

重写onTouchEvent()和onInterceptTouchEvent(),并返回false,如果你根本不需要OnItemTouchListener。 这不会禁用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; } } 

创build扩展RecyclerView类的类

  public class NonscrollRecylerview extends RecyclerView { public NonscrollRecylerview(Context context) { super(context); } public NonscrollRecylerview(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public NonscrollRecylerview(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.NonscrollRecylerview ... ... > ... ... </com.yourpackage.xyz.NonscrollRecylerview > 

我一直在这个问题上挣扎了一段时间,所以我想分享一下我的经验,对于layoutManager解决scheme来说很好,但是如果你想要reEnable滚动,回收站将回到顶部。

到目前为止最好的解决scheme(至less对我来说)是使用@ 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); 

以下是我如何使用数据绑定完成的:

  <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}"/> 

代替“真实”我使用了一个布尔variables根据条件改变,以便回收站视图之间切换被禁用和启用。

写了一个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()