Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/211.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何禁用RecyclerView滚动?_Android_Scroll_Android Recyclerview - Fatal编程技术网

Android 如何禁用RecyclerView滚动?

Android 如何禁用RecyclerView滚动?,android,scroll,android-recyclerview,Android,Scroll,Android Recyclerview,我无法在RecyclerView中禁用滚动。我尝试调用rv.setEnabled(false),但仍然可以滚动 如何禁用滚动?这是一个有点老套的解决方法,但它可以工作;您可以在RecyclerView中启用/禁用滚动 public class RecyclerViewDisabler implements RecyclerView.OnItemTouchListener { @Override public boolean onInterceptTouchEvent(Recyc

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


如何禁用滚动?

这是一个有点老套的解决方法,但它可以工作;您可以在
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.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
并覆盖
canscrollHorizontal()
canscrollVertical()
以禁用滚动

请注意,在开头插入项目不会自动滚动回开头,要避免此问题,请执行以下操作:

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

另一种选择是
SetLayoutFrozed
,但它还有一系列其他副作用

这对我来说很有用:

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

出于某种原因,@Alejandro Gracia answer在几秒钟后才开始工作。 我找到了一个即时阻止RecyclerView的解决方案:


我知道这已经有了一个公认的答案,但解决方案没有考虑到我遇到的用例

我特别需要一个仍然可以点击的标题项,但它禁用了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。这样,它只会禁用滚动,而不会禁用其他任何功能。您仍然能够处理点击或任何其他触摸事件。例如:-

原件: 在这里,使用“IsCrollenabled”标志,您可以临时启用/禁用循环视图的滚动功能

也: 简单覆盖现有实现以禁用滚动并允许单击

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

object : LinearLayoutManager(this){ override fun canScrollVertically(): Boolean { return false } }
真正的答案是

recyclerView.setNestedScrollingEnabled(false);
更多信息请访问

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

创建扩展回收视图的类

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及以上版本:

object : LinearLayoutManager(this){ override fun canScrollVertically(): Boolean { return false } }
不需要java代码。 您可以设置android:nestedScrollingEnabled=“false” 在xml中:


以下是我如何使用数据绑定实现的:

            <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格式的recycleview中即可

 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的仅滚动功能,则可以使用
设置布局冻结(true)回收视图的方法。但不能禁用触摸事件

your_recyclerView.setLayoutFrozen(true);

有一种更直接的方法可以禁用滚动(技术上更确切地说,它是截取滚动事件,并在满足条件时终止),只使用标准功能
RecyclerView
有一个名为
addOnScrollListener(OnScrollListener)
的方法,只要使用这个方法,您就可以阻止它滚动,如下所示:

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
获得机会之前立即停止,那么。。。滚动

注意:为了获得更好的可用性,请尝试使用
gestureelistener
而不是
OnClickListener
,以防止
意外的
点击your_recyclerView.setLayoutFrozen(true);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (viewModel.isItemSelected) {
            recyclerView.stopScroll();
        }
    }
});
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
LinearLayoutManager lm = new LinearLayoutManager(getContext()) {
                @Override
                public boolean canScrollVertically() {
                    return false;
                }
            };
recyclerView.suppressLayout(true)
recyclerView.suppressLayout(false)
        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;
            }
        });
    }
recyclerView.layoutManager = object : LinearLayoutManager(context) {
    override fun canScrollVertically(): Boolean = false
}
recyclerView.suppressLayout(true)
            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;
                }
            }
recyclerView.stopScroll()