Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simultaneous touch events handling on multiple views in Android

Considering the example from the below image,

enter image description here

I'm looking for a solution to pass the touch events from the canvas View to the Viewpager. This is necessary for applying the same amount of zoom on both views at the same time.

Here's the technical description of what's going on,

(Lets consider the view as A, B & C)

A. Parent View

B. View

C. View Pager

Before the dispatchTouchEvent() is called on the children (B & C), the A.dispatchTouchEvent() will first calls A.onInterceptTouchEvent() to see if the view group is interested in intercepting the event.

So if A.onTouchEvent() returns false, then it goes back up to B.onTouchEvent(). If that returns false then it goes back up to C.onTouchEvent() and the dispatching continues as usual.

And upon returning true,

  1. ACTION_CANCEL will be dispatched to all the children.

  2. All the subsequent gesture events (till ACTION_UP/ACTION_CANCEL) will be consumed by the event listeners (OnTouchListener.onTouch()) if defined, else the event handler A.onTouchEvent() at A’s level.

At this point I can pass the events from the parent to the child views but can't let the 2 child view B. & C handle the events together (applying same amount of zoom on both views).

Is there any way to pass the touch events from the parent view to a child one so that they can process the events simultaneously?

Here's my layout setup,

<RelativeLayout
    android:id="@+id/layoutParent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFFFF">

            <com.androidapp.NonSwipeableViewPager
                android:id="@+id/pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:background="@color/transparent" />

            <com.androidapp.DrawingView
                android:id="@+id/drawing"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/transparent" />

</RelativeLayout>
like image 806
Falling Into Infinity Avatar asked Dec 06 '16 10:12

Falling Into Infinity


1 Answers

If I'm not wrong, you want to process the same touch event both on the top and bottom view. According to Android touch architecture, you can't handle touch events from multiple views at the same time. Either you have to process it inside the onTouchEvent() method or pass to the next view. You also need to wait till the top view finish processing the MotionEvent() and let the child view to handle.

Here's a possible solution using RxAndroid approach,

Inside your canvas view's MotionEvent(),

@Override
    public boolean onTouchEvent(MotionEvent event) {

    // process all touch events (UP/DOWN/MOVE)

    //send events as observable
    RxBus.getInstance().sendMotionEvent(event);

    return true;
}

This will observe the motion events and notify all observers.

Now, inside your viewpager's onResume() subscribe for the motion events so that whenever a change is made from the canvas It'll immediately pass the events.

Subscription RxBus _rxBus = RxBus.getInstance();
        subscription = _rxBus.getMotionEvent()
                .subscribe(new Action1<MotionEvent>() {
                    @Override
                    public void call(MotionEvent event) {
                       // call the onTouchEvent of your widget e.g. ImageView and pass the received event
                       // this will apply the same touch event that was applied in the canvas 

                        // .onTouchEvent(event) is important to override the onTouchEvent() of your widget that will use the touch event
                        imageView.onTouchEvent(event);
                    }
            });

The RxBus class is given below,

public class RxBus {

    private static RxBus instance;

    private final PublishSubject<MotionEvent> motion_event = PublishSubject.create();

    public static RxBus getInstance() {
        if (instance == null) {
            instance = new RxBus();
        }
        return instance;
    }

    public void sendMotionEvent(MotionEvent motionEvent) {
        motion_event.onNext(motionEvent);
    }

    public Observable<MotionEvent> getMotionEvent() {
        return motion_event;
    }
}
like image 59
Prokash Sarkar Avatar answered Sep 29 '22 01:09

Prokash Sarkar