防止RecyclerView手动滚动

时间:2017-07-13 15:35:07

标签: android android-recyclerview

我有一个像专辑这样的项目列表,我通过RecyclerView显示它。

此外,每个项目都有一个按钮,通过单击将一些数据发送到服务器,然后滚动到列表中的下一个位置。

所以我的问题是:

如何阻止RecyclerView手动滚动(手势),但如果调用smoothScrollToPosition()方法,则滚动到某个位置?

5 个答案:

答案 0 :(得分:2)

这是水平滚动的解决方案,它允许您关闭滚动,但仍可以通过调用smoothScrollToPosition启用它。它还允许用户与回收者视图中的子视图进行交互。

我发现,其他使临时滚动能够调用smoothScrollToPosition的解决方案具有使用户中断滚动的副作用,即使禁用触摸事件或在recyclerview顶部添加另一个视图也是如此。

关键是要使smoothScrollToPosition正常工作是重写LinearSmoothScroller.calculateDxToMakeVisible并取消对canScrollHorizo​​ntally()的检查

class NoScrollHorizontalLayoutManager(context: Context) : LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) {

    override fun canScrollHorizontally(): Boolean {
        return false
    }

    override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State?, position: Int) {
        val linearSmoothScroller = ForceHorizontalLinearSmoothScroller(recyclerView.context)
        linearSmoothScroller.targetPosition = position
        startSmoothScroll(linearSmoothScroller)
    }
}



class ForceHorizontalLinearSmoothScroller(context: Context) : LinearSmoothScroller(context) {

    override fun calculateDxToMakeVisible(view: android.view.View, snapPreference: Int): Int {
        val layoutManager = layoutManager
        if (layoutManager == null) {
            return 0
        }
        val params = view.layoutParams as RecyclerView.LayoutParams
        val left = layoutManager.getDecoratedLeft(view) - params.leftMargin
        val right = layoutManager.getDecoratedRight(view) + params.rightMargin
        val start = layoutManager.paddingLeft
        val end = layoutManager.width - layoutManager.paddingRight
        return calculateDtToFit(left, right, start, end, snapPreference)
    }
}

编辑: 我发现在滚动过程中点击回收视图时,用户仍然可以停止滚动。解决方法是覆盖RecycleView.onInterceptTouchEvent并防止在进行平滑滚动时或滚动状态设置为SCROLL_STATE_SETTLING时发生事件。 (为此使用RecycleView.addOnItemTouchListener无效,因为RecycleView停止滚动,然后侦听器在RecyleView.onInterceptTouchEvent中返回true。)

class NoScrollRecyclerView : RecyclerView {
    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    override fun onInterceptTouchEvent(e : MotionEvent) : Boolean {
        if (layoutManager?.isSmoothScrolling() == true || scrollState == SCROLL_STATE_SETTLING) {
            return true
        }
        return super.onInterceptTouchEvent(e)
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(e :MotionEvent) : Boolean {
        if (layoutManager?.isSmoothScrolling() == true || scrollState == SCROLL_STATE_SETTLING) {
            return true
        }
        return super.onTouchEvent(e)
    }
}

答案 1 :(得分:1)

您应该覆盖LayoutManager的{​​{1}}。滚动将被禁用,但您仍然可以处理点击或任何其他触摸事件。例如:

RecyclerView

如果你想调用scrollToPosition(),可以这样做:

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

然后使用第一个代码再次禁用它。

答案 2 :(得分:0)

可以通过在列表顶部添加透明覆盖来消除触摸事件来快速破解。或者覆盖dispatchTouchEvent并更改触摸逻辑

答案 3 :(得分:0)

我是通过重写linearLayoutManager和RecyclerView ScrollListener来完成的。

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false) {
        @Override
        public boolean canScrollHorizontally() {
            return canScrolling;
        }

        @Override
        public boolean canScrollVertically() {
            return canScrolling;
        }
    };

rvPassengers.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if(newState == RecyclerView.SCROLL_STATE_IDLE){
                canScrolling = false;
            }
            super.onScrollStateChanged(recyclerView, newState);
        }
    });

答案 4 :(得分:0)

我很乐意改善@Ali提供的答案。有些假设似乎有误导性。

1:使用RecyclerView

变形NestedScrollView
<android.support.v4.widget.NestedScrollView
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <android.support.v7.widget.RecyclerView
      android:id="@+id/recyclerViewForList"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:nestedScrollingEnabled="false"
      />

</android.support.v4.widget.NestedScrollView>

2:将nestedScrollingEnabled设为false

这样做有两种选择;在XML布局或代码中。

XML布局

android:nestedScrollingEnabled="false"

<强>代码

recyclerViewForList.setNestedScrollingEnabled(false);

3:覆盖canScrollVertically

中的LinearLayoutManager
linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
   @Override
   public boolean canScrollVertically() {
      return false;
   }

   //If you want to prevent scrolling horizontally, in my case
   //it was vertically
   @Override
   public boolean canScrollHorizontally() {
      return false;
   }
};