我的RecyclerView
方向为LinearLayoutManager
HORIZONTAL
。其中的每个项目都可以包含交互元素(包括垂直ScrollView
)。有没有办法轻松让RecyclerView
忽略用户在不拦截触摸事件给孩子的情况下水平滚动或投掷RecyclerView
的任何尝试?
我正在以编程方式控制RecyclerView
的滚动,该滚动效果很好,直到用户将其翻转为止。
我尝试过一些非常简单的想法,当我调用smoothScrollToPosition以响应某些事件时,我启用滚动并禁用触摸事件,直到滚动结束。像这样:
private class NoScrollHorizontalLayoutManager extends LinearLayoutManager {
ScrollingTouchInterceptor interceptor = new ScrollingTouchInterceptor();
protected boolean canScroll;
public NoScrollHorizontalLayoutManager(Context ctx) {
super(ctx, LinearLayoutManager.HORIZONTAL, false);
}
public RecyclerView.OnItemTouchListener getInterceptor() {
return interceptor;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
canScroll = true;
super.smoothScrollToPosition(recyclerView, state, position);
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if(state == RecyclerView.SCROLL_STATE_IDLE) {
canScroll = false;
}
}
@Override
public boolean canScrollHorizontally() {
return canScroll;
}
public class ScrollingTouchInterceptor implements RecyclerView.OnItemTouchListener {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return canScrollHorizontally();
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
}
并像这样使用..
NoScrollHorizontalLayoutManager layout = new NoScrollHorizontalLayoutManager(context);
recycler.setLayoutManager(layout);
recycler.addOnItemTouchListener(layout.getInterceptor());
其实几乎有效......但是当光滑的滚动处于运动状态时,我仍然可以通过点击屏幕搞砸程序化滚动。很明显,我错过了一些明显的东西,或者有更聪明的方法来做到这一点。
更新此处找到了非RecyclerView解决方案: How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically?
/**
* ViewPager that doesn't allow swiping.
*/
public class NonSwipeableViewPager extends ViewPager {
public NonSwipeableViewPager(Context context) {
super(context);
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
}
答案 0 :(得分:2)
覆盖onInterceptTouchEvent,可以避免点击行为停止。
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return false;
}
答案 1 :(得分:1)
首先,我不认为这是非编程可实现的。
方式1:简单 - 根据触摸禁用其他视图。
如果用户触摸父级,则禁用子视图滚动。反之亦然
执行此操作的代码
recyclerView.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View p_v, MotionEvent p_event)
{
yourChildView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
方式2:因为您的实施中存在小问题。如果你发布它,有人也可以解决它。
答案 2 :(得分:1)
这是水平滚动的解决方案,它允许您关闭滚动,但仍可以通过调用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)
}
}
答案 3 :(得分:0)
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
答案 4 :(得分:0)
这会产生连续性效果。
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
recyclerView.smoothScrollToPosition(position);
return true;
} else if (action == MotionEvent.ACTION_UP) {
recyclerView.smoothScrollToPosition(position);
return true;
}
return false;
}
});
答案 5 :(得分:-1)
android:nestedScrollingEnabled="false"
在PDF文件的RecyclerView标签中执行上述操作。
答案 6 :(得分:-2)
recyclerView.setNestedScrollingEnabled(false);
有关详细信息,请参阅documentation。