Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jumping ImageView while dragging. getX() and getY() values are jumping

I've created an onTouchListener for dragging Views. Images drag smoothly if I use getRawX() and getRawY(). The problem with that is the image will jump to the second pointer when you place a second pointer down then lift the first pointer.

This onTouchListener attempts to fix that issue by keeping track of the pointerId. The problem with this onTouchListener is while dragging an ImageView, the ImageView jumps around pretty crazily. The getX() and getY() values jump around.

I feel like I'm doing this correctly. I don't want to have to write a custom view for this because I've already implemented a scaleGestureDetector and written a custom rotateGestureDetector that work. Everything works fine but I need to fix the issue I get when using getRawX() and getRawY().

Does anybody know what I'm doing wrong here?

Here's my onTouchListener:

final View.OnTouchListener onTouchListener = new View.OnTouchListener()
{
    @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        relativeLayoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();

        final int action = event.getAction();
        switch (action & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
            {
                final float x = event.getX();
                final float y = event.getY();

                // Where the user started the drag
                lastX = x;
                lastY = y;
                activePointerId = event.getPointerId(0);
                break;
            }
            case MotionEvent.ACTION_MOVE:
            {
                // Where the user's finger is during the drag
                final int pointerIndex = event.findPointerIndex(activePointerId);
                final float x = event.getX(pointerIndex);
                final float y = event.getY(pointerIndex);

                // Calculate change in x and change in y
                final float dx = x - lastX;
                final float dy = y - lastY;

                // Update the margins to move the view
                relativeLayoutParams.leftMargin += dx;
                relativeLayoutParams.topMargin += dy;
                v.setLayoutParams(relativeLayoutParams);

                // Save where the user's finger was for the next ACTION_MOVE
                lastX = x;
                lastY = y;

                v.invalidate();
                break;
            }
            case MotionEvent.ACTION_UP:
            {
                activePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_CANCEL:
            {
                activePointerId = INVALID_POINTER_ID;
                break;
            }
            case MotionEvent.ACTION_POINTER_UP:
            {
                // Extract the index of the pointer that left the touch sensor
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = event.getPointerId(pointerIndex);

                if(pointerId == activePointerId)
                {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    lastX = (int) event.getX(newPointerIndex);
                    lastY = (int) event.getY(newPointerIndex);
                    activePointerId = event.getPointerId(newPointerIndex);
                }
                break;
            }
        }
        return true;
    }
};
image1.setOnTouchListener(onTouchListener);
like image 659
Ben Kane Avatar asked Jul 08 '13 15:07

Ben Kane


2 Answers

The issue was simple, but unexpected. getRawX/Y() returns absolute coordinates, while getX/Y() returns coordinates relative to the view. I would move the view, reset lastX/Y, and the image wouldn't be in the same spot anymore so when I get new values they'd be off. In this case I only needed where I originally pressed the image (not the case when using `getRawX/Y').

So, the solution was to simply remove the following:

// Save where the user's finger was for the next ACTION_MOVE
lastX = x;
lastY = y;

I hope this will help somebody in the future, because I've seen others with this problem, and they had similar code to me (resetting lastX/Y)

like image 108
Ben Kane Avatar answered Oct 20 '22 03:10

Ben Kane


After a lot of research, I found this to be the issue, getRawX is absolute and getX is relative to view. hence use this to transform one to another

//RawX = getX + View.getX

event.getRawX == event.getX(event.findPointerIndex(ptrID1))+view.getX()
like image 27
Maurice Avatar answered Oct 20 '22 02:10

Maurice