防止 RecyclerView 手动滚动

Far*_*ABZ 5 android android-recyclerview

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

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

所以我的问题是:

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

dru*_*dru 6

这是水平滚动的解决方案,它允许您关闭滚动,但仍然通过调用 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑: 我发现用户在滚动过程中点击回收视图时仍然可以停止滚动。修复方法是RecycleView.onInterceptTouchEvent在平滑滚动进行中或滚动状态设置为 时覆盖和阻止事件SCROLL_STATE_SETTLING。(RecycleView.addOnItemTouchListener用于此将不起作用,因为 RecycleView 停止滚动然后侦听器在 中返回 true RecyleView.onInterceptTouchEvent。)

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)
    }
}
Run Code Online (Sandbox Code Playgroud)


NIP*_*HIN 0

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