android – Detect touch event on a view when dragged over from other view-ThrowExceptions

Exception or error:

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

How to solve:

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.

###

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.

###

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.

###

In View A, Override onTouchEvent as follows:

@Override
public boolean onTouchEvent(MotionEvent event) 
{

    float x = event.getRawX();
    float y = event.getRawY();
    if ( (B.getLeft() <= x <= B.getRight()) &&
         (B.getTop() <= y <= B.getBottom())
       )
    {
        Log.i("A", "Motion Event is currently above B");
        B.dispatchTouchEvent(event);
    }

    return true;
}

In View B, override the same method, making sure you return false:

@Override
public boolean onTouchEvent(MotionEvent event) 
{
    //TODO handle touch event
    return false;//this will allow A to continue using the event
}

###

Try using the drag and drop framework.

###

When you are over View B, call it’s onTouch manually.

if (viewBRect.contains(x, y)) {
    viewBsonTouch(view, motionEvent);
}

Leave a Reply

Your email address will not be published. Required fields are marked *