Home » Android » android – How can a ViewGroup intercept all non-scrolling action event, and dispatch only scrolling event to children?-Exceptionshub

android – How can a ViewGroup intercept all non-scrolling action event, and dispatch only scrolling event to children?-Exceptionshub

Posted by: admin February 26, 2020 Leave a comment

Questions:

Currently, in certain situation, our app need to achieve the following thing

  1. Display a semi-transparent overlay layer on the top of the app.
  2. The overlay layer, should intercept all non-scrolling action events (So that children will not receive any non-scrolling events), and dispatch only scrolling event to children?

We can achieve the 1st requirement by using the following XML.

<?xml version="1.0" encoding="utf-8"?>
<com.xxx.InterceptTouchFrameLayout
    android:clickable="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:foreground="#9f000000"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <androidx.recyclerview.widget.RecyclerView />

</com.xxx.InterceptTouchFrameLayout>

enter image description here


Now, we wish to achieve 2nd requirement. Our custom FrameLayout is as follow.

public class InterceptTouchFrameLayout extends FrameLayout {
    public InterceptTouchFrameLayout(@NonNull Context context) {
        super(context);
    }

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

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public InterceptTouchFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // We only receive 2 types of MotionEvent so far.
        //
        // They are MotionEvent.ACTION_DOWN & MotionEvent.ACTION_MOVE

        return super.onInterceptTouchEvent(ev);
    }
}

We aren’t sure how should we only pass “scrolling” event to children, but intercept rest of the events. Our initial trial doesn’t work well.

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        android.util.Log.i("CHEOK", "MotionEvent.ACTION_DOWN");

        // This is non-scrolling event???
        // Do not pass to children.
        return true;
    }

    if (ev.getAction() == MotionEvent.ACTION_MOVE) {
        //
        // WARNING: We will never receive MotionEvent.ACTION_MOVE, after we
        // return true for MotionEvent.ACTION_DOWN.
        //

        android.util.Log.i("CHEOK", "MotionEvent.ACTION_MOVE");

        // This is scrolling event???
        // Let's pass to children.
        return super.onInterceptTouchEvent(ev);
    }

    android.util.Log.i("CHEOK", "UNKNOWN -> " + ev.getAction());

    return super.onInterceptTouchEvent(ev);
}

We return true all time for MotionEvent.ACTION_DOWN, so that children will not receive any “click” event. But, this comes with a side effect too. We will never receive any MotionEvent.ACTION_MOVE too.

Does anyone know, what is the correct implementation, so that we can achieve “a ViewGroup intercept all non-scrolling action event, and dispatch only scrolling event to children” ?


Little background on the problem

We wish to achieve the following effect similar to Todoist – https://youtu.be/EoL0sQRYQe4

As you can see, when the floating action button is tapped, the following will happen

  1. A semi-transparent overlay layer shown
  2. Tap event will not transfer to the child components behind the overlay layer. The overlay layer will handle the tap event, by hiding itself.
  3. Scroll event will scroll the child components (In this case, it is RecyclerView)
How to&Answers: