Detect touch event on a view when dragged over from other view

How do I detect the touch event if the user touches on view A and drags to bottom over the view B. I want to detect the touch event in View B.

I added touch listener in view B but doesn't receive events if the user initially touched A and dragged over the B.

enter image description here


Solution 1:

You can use the code bellow to achive your request:

Method to test view bounds (used in code beloow)

    Rect outRect = new Rect();
    int[] location = new int[2];

    private boolean isViewInBounds(View view, int x, int y){
        view.getDrawingRect(outRect);
        view.getLocationOnScreen(location);
        outRect.offset(location[0], location[1]);
        return outRect.contains(x, y);
    }

Testing with two TextView

    final TextView viewA = (TextView)  findViewById(R.id.textView);
    final TextView viewB = (TextView)  findViewById(R.id.textView2);

Setup viewA

The empty OnClickListener is required to keep OnTouchListener active until ACTION_UP

    viewA.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {}
    });

    viewA.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int x = (int)event.getRawX();
            int y = (int)event.getRawY();
            if(event.getAction() == MotionEvent.ACTION_UP){
                if(isViewInBounds(viewB, x, y))
                    viewB.dispatchTouchEvent(event);
                else if(isViewInBounds(viewA, x, y)){
                    Log.d(TAG, "onTouch ViewA");
                    //Here goes code to execute on onTouch ViewA
                }
            }
            // Further touch is not handled
            return false;
        }
    });

Setup viewB

This is only required if you also want to press on viewB and drag to viewA

    viewB.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {}
    });

    viewB.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int x = (int)event.getRawX();
            int y = (int)event.getRawY();
            if(event.getAction() == MotionEvent.ACTION_UP){
                if(isViewInBounds(viewA, x, y))
                    viewA.dispatchTouchEvent(event);
                else if(isViewInBounds(viewB, x, y)){
                    Log.d(TAG, "onTouch ViewB");
                    //Here goes code to execute on onTouch ViewB
                }
            }
            // Further touch is not handled
            return false;
        }
    });

Regards.

Solution 2:

I'm sure that you need override ViewGroup.dispatchTouchEvent(MotionEvent ev) method in your ViewGroup that contains Views A and B. The original implementation defines the target view when the container receives MotionEvent.getAction() == MotionEvent.ACTION_DOWN and then dispatches all the following touch events to the target view until receives MotionEvent.getAction() == MotionEvent.ACTION_UP or MotionEvent.ACTION_CANCEL.

In your case the target view is A or the containter itself (depands on your container onInterceptTouchEvent(MotionEvent ev) method implementation). So you should override such behaviour and dispatch touch events not only to the target view, but also to all the views, that under the touched area (for example to view B).

If you are interested you can share code sample and I'll try to help you further.

Solution 3:

If you are returning true from the onTouchEvent of the view A then the event is not propagated. In this particular case when A is below B return false from onTouch of view A.

It would also help if you can post some code.