You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RecyclerView中CustomView触摸处理与ItemTouchHelper的冲突问题

解决方案

1. 修正CustomView的事件拦截逻辑

在onInterceptTouchEvent中,必须在ACTION_DOWN事件触发时立即阻止父布局(RecyclerView)拦截事件——因为ACTION_DOWN是触摸事件序列的起点,父布局会在这个阶段判断是否接管后续事件,晚一步都会导致事件被抢。

public class CustomView extends View {
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 捕获ACTION_DOWN时立即禁用父布局的事件拦截
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            getParent().requestDisallowInterceptTouchEvent(true);
        }
        // 拦截所有事件,交由自身onTouchEvent处理
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                // 在这里实现你的水平拖拽逻辑
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // 触摸结束后恢复父布局的事件拦截权限,避免影响其他条目
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        // 消费所有触摸事件
        return true;
    }
}

2. 让ItemTouchHelper避开CustomView的长按拖拽

自定义ItemTouchHelper.SimpleCallback,重写isLongPressDragEnabled方法,判断当前触摸的条目是否使用了CustomView,如果是则禁用长按拖拽,彻底避免ItemTouchHelper和CustomView抢事件。

public class MyItemTouchCallback extends ItemTouchHelper.SimpleCallback {
    private final RecyclerView mRecyclerView;

    public MyItemTouchCallback(int dragDirs, int swipeDirs, RecyclerView recyclerView) {
        super(dragDirs, swipeDirs);
        mRecyclerView = recyclerView;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        // 获取当前触摸的子View
        View touchedView = mRecyclerView.findChildViewUnder(mRecyclerView.getTouchX(), mRecyclerView.getTouchY());
        if (touchedView != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(touchedView);
            // 判断条目根布局是否为CustomView
            if (holder.itemView instanceof CustomView) {
                return false; // 禁用长按拖拽
            }
        }
        return true; // 其他条目保留长按拖拽功能
    }

    // 以下是原有逻辑,保持不变
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // 实现条目拖拽交换逻辑
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // 实现水平滑动逻辑
    }
}

3. 绑定ItemTouchHelper时传入RecyclerView

初始化ItemTouchHelper时把RecyclerView传进去,确保isLongPressDragEnabled能准确获取到当前触摸的条目:

ItemTouchHelper touchHelper = new ItemTouchHelper(new MyItemTouchCallback(
        ItemTouchHelper.UP | ItemTouchHelper.DOWN,
        ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT,
        recyclerView
));
touchHelper.attachToRecyclerView(recyclerView);

内容的提问来源于stack exchange,提问作者Basti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:32:27