我有一个像专辑这样的项目列表,我通过RecyclerView显示它。
此外,每个项目都有一个按钮,通过单击将一些数据发送到服务器,然后滚动到列表中的下一个位置。
所以我的问题是:
如何阻止RecyclerView手动滚动(手势),但如果调用smoothScrollToPosition()方法,则滚动到某个位置?
答案 0 :(得分:2)
这是水平滚动的解决方案,它允许您关闭滚动,但仍可以通过调用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)
}
}
答案 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提供的答案。有些假设似乎有误导性。
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>
nestedScrollingEnabled
设为false 这样做有两种选择;在XML布局或代码中。
XML布局
android:nestedScrollingEnabled="false"
<强>代码强>
recyclerViewForList.setNestedScrollingEnabled(false);
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;
}
};