如何将点击事件传递给 RecyclerView 的项目?

How to pass a click event to RecyclerView's items?

我有一个普通的 RecyclerView,在它上面有一个实现 GestureListener 的透明 View,它的大小基本上与 RecyclerView 相同。

GestureListener 将监听滚动和滑动手势,并将此 MotionEvent 传递给它下面的 RecyclerView

我已经让 RecyclerView 能够滚动和滑动。但是,我也找不到将点击事件传递给 RecyclerView 的方法。

我已经知道这是因为ACTION_DOWN消耗在了GestureListener。事实上,GestureListener 有一个 onSingleTap() 方法供您重写,每当我执行单击时都会调用此方法。

根据 this post,我尝试为我的 itemView 设置一个 OnTouchListener 并监听 ACTION_UP 事件。但是,从未调用 onTouch() 方法。

以下是我的做法:
1.在透明的GestureListener中创建一个回调

   @Override
    public boolean onSingleTapUp(MotionEvent e) {
        if (scrollDetector == null) return false;
        scrollDetector.onSingleTap(e);
        return true;
    }
  1. 在activity配置回调,将MotionEvent传给RecyclerView

    @Override
    public void onSingleTap(MotionEvent e) {
        mRecyclerView.onTouchEvent(e);
    }
    
  2. OnTouchListener设置为适配器中的itemView:

    itemView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                v.performClick();
                return true;
            }
            return false;
        }
    });
    

使用调试器,我可以看到调用了 mRecyclerView.onTouchEvent(e);但是没有调用itemView的onTouch()

所以...我应该如何正确地将 MotionEvent 传递给 itemView?

你可能会问 - "Why do you place a GestureListener on top of the RecyclerView?"
这是因为我需要在滚动 RecyclerView 时更改 RecyclerView 的高度。但是,如果我使用 RecyclerViewaddOnScrollListener 执行此操作,dy 的值将在负值和正值之间波动,因为 dy 也受其高度影响。而且波动也会反映到UI.
因此,我需要一个滚动检测器,它在滚动时不会改变其高度,只需通过编程调用 scrollBy()fling().

将滚动和滑动值传递给 RecyclerView

你应该知道recyclerview的event.Ifrecyclerview可以在滚动视图时移动,它会调用onInterceptTouchEvent()和return true拦截event.So你无法获得ACTION_MOVE event.Maybe 你应该重写 recyclerview 的 onInterceptTouchEvent() 和 return false。然后你可以在你的itemView的方法中得到所有的事件。

愚蠢的我。我应该使用 dispatchTouchEvent(MotionEvent e) 而不是 onTouchEvent(MotionEvent e).

然而,这还不够。
使用来自 GestureListener 的 MotionEvent 简单地调用 dispatchTouchEvent(e) 是行不通的,因为 e 是一个 ACTION_UP 事件。

要模拟点击,您需要 ACTION_DOWNACTION_UP

并且itemView不需要设置OnTouchListener因为你已经模拟了

代码:

        @Override
        public void onSingleTap(MotionEvent e) {
            long downTime = SystemClock.uptimeMillis();
            long upTime = downTime + 100;
            MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,
                    e.getX(), e.getY(), 0);
            mRecyclerView.dispatchTouchEvent(downEvent);
            MotionEvent upEvent = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP,
                    e.getX(), e.getY(), 0);
            mRecyclerView.dispatchTouchEvent(upEvent);
            downEvent.recycle();
            upEvent.recycle();
        }