background

Recently, I have been developing a recording function. Generally, button starts recording when it is in Action_Down and stops recording when it is in Action_Up or Action_Cancel.

At this time, a problem was found. When the button was in recycelView, if the vertical Action_Move of the finger exceeded a certain range, onTouchListener would receive the Action_Cancel event to prevent continued recording. Not when the component is within a RelativeLayout or LinearLayout.

To analyze problems

1. Locate the fault

RecycleView is a RelativeLayout ViewGroup that responds differently to a RelativeLayout ViewGroup. We can see that RecycleView is a RecycleView problem.

The current thread is that when the Button RecycleView is used, it receives an Action_Cancel callback. The RecycleView is used to distribute events. When the RecycleView is used, it sends an Action_Cancel method

2. RecycleView onInterceptTouchEvent

The onInterceptTouchEvent of RecycleVIew does something about Action_Move

public boolean onInterceptTouchEvent(MotionEvent e) { ... case 2: // Action_Move int index = e.findPointerIndex(this.mScrollPointerId); if (index < 0) { Log.e("RecyclerView", "Error processing scroll; pointer index for id " + this.mScrollPointerId + " not found. Did any MotionEvents get skipped?" ); return false; } int x = (LLDB)(LLDB + LLDB); Int y = (int)(LLDB (index) + 0); if (this.mScrollState ! = 1) { int dx = x - this.mInitialTouchX; int dy = y - this.mInitialTouchY; boolean startScroll = false; if (canScrollHorizontally && Math.abs(dx) > this.mTouchSlop) { this.mLastTouchX = x; startScroll = true; } if (canScrollVertically && Math.abs(dy) > this.mTouchSlop) { this.mLastTouchY = y; startScroll = true; } if (startScroll) { this.setScrollState(1); } } break; . return this.mScrollState == 1; }Copy the code

So when I’m doing ActionMove, it’s a vertical RecycleView, so it’s going to pass the judgment canScrollVertically && math.abs (dy) > this.mtouchSlop, so it’s like this: When we think we are doing voice long press sliding, because drag beyond a certain range, RecycleView treats it as a sliding list operation, so the mScrollState is set to 1, onInterceptTouchEvent returns true, eats the event itself.

The solution

Understand the problem, the solution is very simple, I am a custom RecycleView plus a symbol bit judgment, in the button long press to prevent RecycleView intercept events, long press after release

public class RateRecyclerView extends RecyclerView {
    public RateRecyclerView(@NonNull Context context) {
        super(context);
    }

    public RateRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public RateRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private boolean needIntercept = true;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return needIntercept && super.onInterceptTouchEvent(ev);
    }

    public void disableIntercept() {
        this.needIntercept = false;
    }

    public void enableIntercept() {
        this.needIntercept = true;
    }
}
Copy the code