Как отключить прокрутку 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;
}
};
Для 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;
}
});
}