Java 从RecyclerView中的项触发单击并拖动操作
我有一个垂直滚动的RecyclerView,我想允许点击上面的项目并重新排序 RecyclerView中的每个项目在左侧都有一个“StatusIndicator”(从AppCompatImageButton继承)。我已经在StatusIndicator中添加了一个手势检测器,除了垂直拖动没有被发送到StatusIndicator之外,这似乎是可行的 我看到的行为是,如果我尝试在StatusIndicator上垂直滚动(打算触发拖动),则不会触发拖动,也不会滚动RecyclerView。如果我继续滚动手势,但突然水平滚动,我可以拖动项目 我假设ACTION_DOWN事件到达StatusIndicator的GestureDetector以触发拖动,但RecyclerView捕获以下(主要是垂直)ACTION_MOVE(假设它需要处理垂直滚动)。一旦手势涉及更多的水平移动而非垂直移动,RecyclerView::onInterceptTouchEvent将不再捕获事件(在调试中确认),然后动作将按预期发送到状态指示器 这里的正确方法是什么Java 从RecyclerView中的项触发单击并拖动操作,java,android,android-recyclerview,Java,Android,Android Recyclerview,我有一个垂直滚动的RecyclerView,我想允许点击上面的项目并重新排序 RecyclerView中的每个项目在左侧都有一个“StatusIndicator”(从AppCompatImageButton继承)。我已经在StatusIndicator中添加了一个手势检测器,除了垂直拖动没有被发送到StatusIndicator之外,这似乎是可行的 我看到的行为是,如果我尝试在StatusIndicator上垂直滚动(打算触发拖动),则不会触发拖动,也不会滚动RecyclerView。如果我继续
StatusIndicator.java的相关位:
class StatusIndicator extends AppCompatImageButton {
class GestureTouch extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (mStatusIndicatorListener != null)
mStatusIndicatorListener.incrementStatus();
createDrawableState();
return true;
}
@Override
public boolean onScroll (MotionEvent e1,
MotionEvent e2,
float distanceX,
float distanceY) {
mStatusIndicatorListener.startDrag();
return true;
}
}
private StatusIndicatorListener mStatusIndicatorListener;
private GestureDetector mTouchDetector;
public StatusIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchDetector = new GestureDetector(context,new GestureTouch());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mTouchDetector.onTouchEvent(event);
return true;
}
我相信发生的事情是,任何动作移动事件都会进入堆栈,并被RecyclerView在其onInterceptTouchEvent方法中捕获。在此RecyclerView中,LayoutManager.CanScrollVertical()用于确定RecyclerView应捕获事件 最后,我继承了LinearLayoutManager并重写了canScrollVertically(),因此可以通过调用新方法手动阻止它。然后,在RecyclerView.onInterceptTouchEvent中,我检查了传入的ACTION_DOWN事件是否超过了StatusIndicator,如果是,则强制RecyclerView.LayoutManater.CanScrollVertical()返回false,直到下一个ACTION_DOWN事件 这是一个相当粗糙的解决方案,但看起来很健壮。如果有人提出一个“合适的”解决方案,我会很乐意看到的
新的布局管理器:
public class ListLayoutManager extends LinearLayoutManager {
boolean mScrollBlocked;
public ListLayoutManager(Context context) {
super(context);
mScrollBlocked = false;
}
@Override
public boolean canScrollVertically() {
return (!mScrollBlocked && super.canScrollVertically());
}
public void blockScrolling() {
mScrollBlocked = true;
}
public void unblockScrolling() {
mScrollBlocked = false;
}
}
已覆盖onInterceptTouchEvent的扩展回收视图:
ListLayoutManager mListLayoutManager;
public ListRecyclerView(Context context) {
super(context);
}
public ListRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// We override touch handling so the RecyclerView doesn't handle
// anything which occurs over the StatusIndicator.
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
mListLayoutManager.unblockScrolling();
View child = findChildViewUnder(e.getX(), e.getY());
if (child != null) {
StatusIndicator statusInd = child.findViewById(R.id.rowStatus);
if ((statusInd != null) &&
(e.getX() <= statusInd.getWidth())) {
mListLayoutManager.blockScrolling();
}
}
}
return super.onInterceptTouchEvent(e);
}
public void setListLayoutManager(ListLayoutManager lm) {
mListLayoutManager = lm;
setLayoutManager(mListLayoutManager);
}
}
ListLayoutManager-mListLayoutManager;
公共ListRecyclerView(上下文){
超级(上下文);
}
公共ListRecyclerView(上下文、属性集属性){
超级(上下文,attrs);
}
公共ListRecyclerView(上下文、属性集属性、int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
}
//我们覆盖触摸处理,因此RecyclerView无法处理
//状态指示器上发生的任何事件。
@凌驾
公共布尔值onInterceptTouchEvent(运动事件e){
如果(例如getActionMasked()==MotionEvent.ACTION\u DOWN){
mListLayoutManager.unbocrolling();
View child=findChildViewUnder(e.getX(),e.getY());
if(child!=null){
StatusIndicator statusInd=child.findViewById(R.id.rowStatus);
if((statusInd!=null)&&
(e.getX()