如何禁用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
,但它带有一堆其他的副作用。
你也可以在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()