Как отключить прокрутку RecyclerView?

Я не могу отключить прокрутку в RecyclerView, Я пробовал звонить rv.setEnabled(false) но я все еще могу прокрутить.

Как я могу отключить прокрутку?

34 ответа

Решение

Для этого вам следует переопределить макет менеджера вашего повторного просмотра. Таким образом, будет отключена только прокрутка, ни одна из других функций. Вы по-прежнему сможете обрабатывать нажатия или любые другие события касания. Например:-

Оригинал:

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

Настоящий ответ

recyclerView.setNestedScrollingEnabled(false);

Больше информации в документации

Для 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">

Это немного хакерский обходной путь, но он работает; Вы можете включить / отключить прокрутку в 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;
      }
  });

Как setLayoutFrozen устарело, вы можете отключить прокрутку, заморозив RecyclerView, используя suppressLayout.

Заморозить:

recyclerView.suppressLayout(true)

Чтобы разморозить:

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

Вы можете отключить прокрутку, заморозив RecyclerView.

Чтобы заморозить:recyclerView.setLayoutFrozen(true)

Разморозить: recyclerView.setLayoutFrozen(false)

Существует очень простой ответ.

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

Приведенный выше код отключает вертикальную прокрутку RecyclerView.

В Kotlin, если вы не хотите создавать дополнительный класс только для установки одного значения, вы можете создать анонимный класс из LayoutManager:

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

Создать класс, который расширяет класс 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 >

Если вы просто отключите только функцию прокрутки RecyclerView тогда вы можете использовать setLayoutFrozen(true); метод RecyclerView, Но нельзя отключить сенсорное событие.

your_recyclerView.setLayoutFrozen(true);

Написал котлинскую версию:

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

в XML:-

Можете добавить

android:nestedScrollingEnabled="false"

в дочернем XML-файле макета RecyclerView

или же

в Java:-

childRecyclerView.setNestedScrollingEnabled(false);

к вашему RecyclerView в коде Java.

Использование ViewCompat (Java):-

childRecyclerView.setNestedScrollingEnabled(false); будет работать только в android_version>21 устройства. для работы на всех устройствах используйте следующее

ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);

Другая альтернатива setLayoutFrozen, но это идет с кучей других побочных эффектов.

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html

Расширить 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);
          }
        }
      }
    });
  }

Я знаю, что на это уже есть принятый ответ, но решение не учитывает сценарий использования, с которым я столкнулся.

Мне особенно нужен был элемент заголовка, который можно было нажимать, но при этом отключить механизм прокрутки в 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.suppressLayout(true)

В методе действия onCreate вы можете просто сделать:

recyclerView.stopScroll()

и он перестает прокручиваться.

Переопределите onTouchEvent() и onInterceptTouchEvent() и верните false, если вам совсем не нужен OnItemTouchListener. Это не отключает OnClickListeners ViewHolders.

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

Просто добавьте это в свой recycleview в 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">

Вы можете добавить эту строку после настройки вашего адаптера

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

Теперь ваш переработчик будет работать с плавной прокруткой

Почему-то ответ @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) {
            }
        });

Добавлять

android:descendantFocusability="blocksDescendants"

в вашем дочернем элементе SrollView или NestedScrollView (и любой родительский элемент ListView, recyclerview и gridview любой)

Существует более простой способ отключить прокрутку, используя только стандартные функции. 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, не теряя smoothScrollToPosition или любой другой метод "перехода в позицию", я бы рекомендовал расширить RecyclerView класс, переопределив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;
                }
            }

Я боролся с этой проблемой в течение часа, поэтому я хотел бы поделиться своим опытом. Для решения 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);

Подведение итогов ответов на этот вопрос.

Самый простой и лучший способ отключить прокрутку recyclerView:

      yourRecyclerView.layoutmanager = object : LinearLayoutManager(context) {
        override fun canScrollVertically(): Boolean = false
    }

Следующие решения работают, если recyclerView помещен внутри вложенногоScrollView:

      yourRecyclerView.isNestedScrollingEnabled = false

android:descendantFocusability="blocksDescendants"

android:nestedScrollingEnabled="false"

Примечание. Каждое решение работает только в том случае, если recyclerView помещен внутри вложенногоScrollView.

Вот как я это сделал с привязкой данных:

            <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" я использовал логическую переменную, которая изменялась в зависимости от условия, чтобы представление рециркулятора переключалось между отключением и включением.

Чтобы остановить прокрутку прикосновением, но продолжайте прокручивать с помощью команд:

если (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;
            }
        });
    }
Другие вопросы по тегам