RecyclerViewのスクロールを無効にする方法は?


221

でのスクロールを無効にできませんRecyclerView。電話をかけrv.setEnabled(false)てみましたが、スクロールできます。

スクロールを無効にするにはどうすればよいですか?


1
RecyclerViewスクロールしたくない場合の使用目的は何ですか?
CommonsWare、2015年

16
@CommonsWare、たとえば、子の1つでカスタムアニメーションを実行している間は、一時的に無効にしたいだけです。
Zsolt Safrany、2015年

1
ああ、わかりました、それは理にかなっています。必要に応じてとを切り替えViewRecyclerView、の上に透明部分を置いたVISIBLEGONE思いますが、袖口を外すと、あなたのアプローチは妥当なようです。
CommonsWare、2015年

これがより良い解決策を見つけるのに役立つことを願っています。
Saiteja Parsi

1
@CommonsWare、例えば私がそれを必要とするものはここにあります。RecyclerViewで画像を一度に1つずつ表示する必要があります。部分的に表示される画像はなく、ビューポートに1つだけ表示します。左側と右側には、ユーザーがナビゲートできる矢印があります。現在表示されている画像(さまざまなタイプの画像)に応じて、RecyclerView以外のいくつかのものがトリガーされます。お客様が求めるデザインです。
Varvara Kalinina 2016

回答:


368

このためには、recycleviewのlayoutmanagerをオーバーライドする必要があります。このようにして、スクロールを無効にするだけで、他の機能は無効にします。クリックやその他のタッチイベントは引き続き処理できます。例えば:-

元の:

 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」フラグを使用して、リサイクルビューのスクロール機能を一時的に有効/無効にすることができます。

また:

既存の実装を単純にオーバーライドして、スクロールを無効にし、クリックを許可します。

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

2
クリックを許可している間、スクロールが無効になるため、これが正しい答えになるはずです。
Jared Burrows 2016年

10
デフォルトのLayoutMangerでスクロールを無効にすることはすでに存在しているはずです。APIのユーザーはこれを行う必要はありません。でも答えてくれてありがとう!
Martin O'Shea

1
特定のアイテムからのみスクロールを無効にするにはどうすればよいですか?つまり、下(または上)にスクロールできますが、再度有効にするまでブロックされますか?
android開発者

2
これにより、smoothScrollToPositionも無効になります
Mladen Rakonjac '29

4
あなたはkotlinバージョンオブジェクトを追加します:LinearLayoutManager(this){オーバーライドfun canScrollVertically():Boolean {return false}}
amorenew

149

本当の答えは

recyclerView.setNestedScrollingEnabled(false);

ドキュメントの詳細


39
これにより、すべてのスクロールではなく、ネストされたスクロールのみが無効になります。特に、RecyclerViewがScrollView内にあるが画面全体に表示されない場合、ScrollViewはスクロールせず(コンテンツが画面に収まります)、RecyclerViewにスクロールUIが表示されます(たとえば、スクロールしようとするとリストの終わりの効果) )大きくなってもスクロールしません。LayoutManagerを拡張すると、実際に機能します。
personne3000

3
@ personne3000 recyclerView.setHasFixedSize(true)がそのための仕事をしていると思います。編集:これをsetFillViewport(true)と組み合わせて使用​​するので、2つのうちどちらが修正するのか実際にはわかりません。
mDroidd 2016

5
これは私にとってはうまく機能しますが、「RecyclerView」は「ScrollView」を使用するFragmentレイアウト内にあったため、ここで説明するように、「NestedScrollView」によって「ScrollView」を変更する必要がありました:stackoverflow.com/a/38088902/618464
educoutinho

1
以下のための完全なクラス名を使用することを忘れないでくださいNestedScrollViewandroid.support.v4.widget.NestedScrollView:、ここで説明したように、chessdorkによってstackoverflow.com/questions/37846245/...
gustavoknz

何が悪いのかを理解するために4時間を費やした後、これは私の問題を解決しました。私の場合、MotionLayout内でrecyclerviewを使用しています。そして、motion:touchAnchorId = "@ id / swipe_area"を追加することにより、上にドラッグするスワイプ領域のみを追加しました。正常に動作しますが、recyclerviewの空の領域に触れたときにもトリガーされます。他のスワイプ可能な要素でmotionLayoutを使用するときは注意してください。
O. Kumru

73

REAL REALの答えは次のとおり です。API21以降の場合:

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

11
これは受け入れられる答えであると思います。クラスで努力することなく、スクロールを無効にできますが、レイアウトでタッチは許可されます。
VipiNネギ

21未満のAPIはどうなりますか?
Mouaad Abdelghafour AITALI

使用できる下位APIの@pic:recyclerView.setNestedScrollingEnabled(false);
Milad Faridnia

1
私に受け入れられた答え。
フェルナンドトーレス

1
これは最良かつ最も簡単な答えであり、不必要なコード汚染や無限のクラス拡張パターンを回避します。
ラファエルC

52

これは少しハッカ的な回避策ですが、機能します。でスクロールを有効/無効にできます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 

8
これにより、アイテムのクリックも無効になりますか?
Jahir Fiquitiva、2015

@JahirFiquitivaはい。「これはすべてのタッチイベントを盗む空のRecyclerView.OnItemTouchListenerです」
最大

1
これにより、親ビューのスクロールも無効になります
Jemshit Iskenderov

これによりアイテムのクリックも無効になります
Muhammad Riyaz

1
クリーンなソリューションがあるのに、(副作用のある)ハックな回避策を使用するのはなぜですか?LayoutManagerをオーバーライドするだけです(他の回答を参照)
personne3000

37

これは私にとってはうまくいきます:

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

11
これにより、すべてのタッチが無効になります。
Jared Burrows 2016年

1
ナイストリック!再度有効にするには、onTouchListenerのonTouchを再設定してfalseを返すだけです
HendraWD

Custom view 'RecyclerView' has setOnTouchListener called on it but does not override performClick
ええと

あなたは@HendraWDは、上記のコメントで述べたのと同じ警告を受けている場合は、この質問の答えを見てみましょう:stackoverflow.com/questions/46135249/...
ニコラス・カラスコ

1
trueを返す代わりに、あらゆる種類のタッチイベントを無効にするreturn e.getAction() == MotionEvent.ACTION_MOVE;代わりにreturn true;、スクロール/スワイプイベントのみがキャンセルされるのではなく。
Toufic Batache

15

RecyclerViewをフリーズすることでスクロールを無効にできます。

凍結するには: recyclerView.setLayoutFrozen(true)

解凍するには: recyclerView.setLayoutFrozen(false)


1
注:RecyclerViewがフリーズされている場合、子ビューは更新されません。すべてのアイテムを表示するのに十分なスペースが画面にある場合、スクロールを無効にする必要があります。ああ...このタスクに最適なAndroid API ...
Oleksandr Nos

1
API 28で非推奨
OhhhThatVarun

13

拡張クラスを作成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();
    }
}

これはスクロールイベントを無効にしますが、クリックイベントは無効にしません

これをXMLで使用して、以下を実行します。

  <com.yourpackage.xyx.NonScrollRecyclerView 
     ...
     ... 
  />

ありがとう!これは、内部スクロールせずに、コンテンツに応じてリサイクラービューを完全な高さにする場合に必要です。:)
Rahul Rastogi

ただし、このリサイクラービューがスクロールビュー(例:ScrollView)内にある場合、レイアウトマネージャーはcanScrollVertically()メソッドをオーバーライドして、そこからfalseを返す必要があります。
Rahul Rastogi

@RahulRastogiはScrollViewではなくNestedScrollViewを使用
Ashish

@AshishMangaveさん、プログラムで再度有効にする方法を教えてください
Shruti

@Shrutiプログラムでこれを行うことはできません。bcz recyclerviewのonMeasureメソッドを直接オーバーライドします。このrecyclerView.setNestedScrollingEnabled(false)を試すことができます。これは役立ちます
Ashish

11

あなただけ無効にした場合のみ、スクロール機能RecyclerViewあなたが使用できるsetLayoutFrozen(true);方法をRecyclerView。ただし、タッチイベントを無効にすることはできません。

your_recyclerView.setLayoutFrozen(true);

このメソッドは非推奨です。別のものを提案できますか?
Aiyaz Parmar

API 28で非推奨
OhhhThatVarun

9
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            // Stop only scrolling.
            return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
        }
    });


タッチすると、smoothScrollToPosition()のスクロールを中止します。
ypresto

プログラムでスクロールできるが、ユーザーのスクロールは回避できるため、これは私にとって最良のソリューションです。
Miguel Sesma

7

本当に簡単な答えがあります。

LinearLayoutManager lm = new LinearLayoutManager(getContext()) {
                @Override
                public boolean canScrollVertically() {
                    return false;
                }
            };

上記のコードは、RecyclerViewの垂直スクロールを無効にします。



6

コトリン版を書いた:

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()

5

を拡張し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);
          }
        }
      }
    });
  }

1
これにより、smoothScrollToPositionも無効になります
Mladen Rakonjac、2017年

5

私はこれがすでに受け入れられた答えを持っていることを知っていますが、解決策は私が遭遇したユースケースを考慮していません。

私は特に、まだクリック可能でありながら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) {

    }
});

何らかの理由で、これを機能させるために移動せずに、右クリックする必要があります。
Jared Burrows 2016年

良い点は、@ JaredBurrowsです。これは、ACTION_MOVEを無視しているためです。タッチが自然に感じられるようにするには、タッチしてから画面上でわずかに動くまでの間にある程度の余裕があります。残念ながら、私はその問題を解決することができませんでした。
Ryan Simon

ありがとう、まさに私が必要とするもの!
学生、

5

setLayoutFrozen推奨されていません、あなたは使用してRecyclerViewを凍結することによりスクロールを無効にすることができますsuppressLayout

凍結するには:

recyclerView.suppressLayout(true)

解凍するには:

recyclerView.suppressLayout(false)

4

XMLで:-

あなたは付け加えられます

android:nestedScrollingEnabled="false"

子RecyclerViewレイアウトXMLファイル内

または

Javaで:-

childRecyclerView.setNestedScrollingEnabled(false);

JavaコードでRecyclerViewに。

ViewCompat(Java)の使用:-

childRecyclerView.setNestedScrollingEnabled(false);android_version> 21デバイスでのみ機能します。すべてのデバイスで作業するには、次を使用します

ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);


すべてのAPIがカバーされているExcelentを起動する必要があります。
リカール

3

なんらかの理由で、@ 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) {
            }
        });

3

onTouchEvent()とonInterceptTouchEvent()をオーバーライドし、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;
    }
}

3

アダプタを設定した後でこの行を追加できます

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

これで、recyclerviewはスムーズスクロールで動作します


2

私はこの問題で数時間苦労してきました。そこで、私の経験を共有したいと思います。layoutManagerソリューションの場合は問題ありませんが、再有効化したい場合は、リサイクラーを上にスクロールしてスクロールします。

これまでの最善の解決策は(少なくとも私にとっては)@Zsolt Safranyメソッドを使用することですが、ゲッターとセッターを追加することで、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);

2

Kotlinでは、1つの値を設定するためだけに追加のクラスを作成したくない場合は、LayoutManagerから匿名クラスを作成できます。

recyclerView.layoutManager = object : LinearLayoutManager(context) {
    override fun canScrollVertically(): Boolean = false
}

1

これは、データバインディングを使用してどのように実行したかです。

            <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」の代わりに、条件に基づいて変更されるブール変数を使用して、リサイクラービューが無効と有効との間で切り替わるようにしました。


1

複数のRecycleViewを含むフラグメントに遭遇したため、各RecycleViewに1つのスクロールバーではなく、1つのスクロールバーしか必要ありません。

したがって、2つのRecycleViewを含む親コンテナーにScrollViewを配置して、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" />

1

追加

android:descendantFocusability="blocksDescendants"

SrollViewまたはNestedScrollViewの子(およびListViewの親、recyclerview、gridviewのいずれか)


1

標準機能だけを使用して、スクロールを無効にする簡単な方法があります(技術的には、スクロールイベントをインターセプトして、条件が満たされたときに終了することです)。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誤って別の項目にスクロールすることで邪魔されることなく 、その中の項目の1つをクリックしたときにスクロールを無効にして、その項目でいくつかのアクションを実行できるようにしたいとします。アイテムを再度クリックして、スクロールを有効にします。そのためには、OnClickListener内のすべてのアイテムにアタッチする必要があるためRecyclerView、アイテムをクリックすると、isItemSelectedからfalseに切り替わりますtrue。この方法であなたは、スクロールしようとすると、RecyclerView自動的にメソッドを呼び出しますonScrollStateChangedし、以降isItemSelectedに設定true、それは前に、すぐに停止しますRecyclerView...よくスクロールに、チャンスを得ました。

注:使いやすさを高めるために、クリックを防止するGestureListener代わりにOnClickListenerを使用してくださいaccidental


stopScroll()スクロールをフリーズするのではなく、スクロールrecyclerviewを停止/停止するだけです。
ファリド

@FARID、はい、このメソッドは進行中のスクロールを停止するだけで、この特定のケースでは、ユーザーがRecyclerViewコンテンツをにisItemSelected設定してスクロールしようとするたびに停止しtrueます。それ以外の場合は、スクロールを無効にするにはカスタムRecyclerViewが必要です。このソリューションが提供する追加機能が少しだけ必要だったので、それを避けたかったのです。
Tim Jorjev

0

これを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">

0

タッチによるスクロールを停止するが、コマンドを介してスクロールを続ける場合:

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;
            }
        });
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.