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