这是一个水平滚动的解决方案,允许您关闭滚动,但仍然通过调用 smoothScrollToPosition 来启用它。它还允许用户与回收器视图中的子视图交互。
我发现其他临时启用滚动以调用 smoothScrollToPosition 的解决方案具有让用户中断滚动的副作用,即使在禁用触摸事件或在 recyclerview 顶部添加另一个视图时也是如此。
让 smoothScrollToPosition 起作用的关键是覆盖 LinearSmoothScroller.calculateDxToMakeVisible 并取消对 canScrollHorizontally() 的检查
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)
}
}