Alexander Farber
Alexander Farber

Reputation: 22958

Dragging Drawable on Canvas - works, but the position is not exact

I have programmed a simple test app, where Drawable objects (the yellow translucent tiles at the screenshot below) can be dragged around on a scrollable and scallable (by using Matrix) Canvas:

Emulator screenshot

Here is the code handling dragging:

private Drawable mDragged = null;
private float mPrevX;
private float mPrevY;

public boolean onTouchEvent(MotionEvent e) {
    // Convert touch coordinates to Canvas coordinates
    float[] point = new float[] {e.getX(), e.getY()};
    Matrix inverse = new Matrix();
    mMatrix.invert(inverse);
    inverse.mapPoints(point);
    float x = point[0];
    float y = point[1];

    switch (e.getAction()) {
    case MotionEvent.ACTION_DOWN:
        Drawable tile = hitTest(x, y);
        if (tile != null) {
            mDragged = tile;
            mPrevX = x;
            mPrevY = y;
            return true;
        }
    break;
    case MotionEvent.ACTION_MOVE:
        if (mDragged != null) {
            float dX = x - mPrevX;
            float dY = y - mPrevY;
            mPrevX = x;
            mPrevY = y;

            Rect rect = mDragged.copyBounds();
            rect.left += dX;
            rect.top += dY;
            rect.right = rect.left + mDragged.getIntrinsicWidth();
            rect.bottom = rect.top + mDragged.getIntrinsicHeight();
            mDragged.setBounds(rect);

            invalidate();
            return true;
        }
    break;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:
        if (mDragged != null) {
            mDragged = null;
            return true;
        }
    break;
    }
    // Handle Canvas scrolling and scaling here
}

It works, but I have a problem - when I touch a tile and then drag it around - the tile departs from my finger (or from my mouse pointer, when using Android emulator).

I.e. the distance between the dragged Drawable and the finger (or mouse pointer - as can be seen on the above screenshot) increases, while it is being dragged around.

This can't be a multi-touch related issue - because there is only single touch on the emulator.

What is the root cause here?

Upvotes: 0

Views: 391

Answers (1)

JstnPwll
JstnPwll

Reputation: 8685

Just a hunch here, but it's probably due to two things being compounded together:

  1. Your coordinates are float values, but the Rect consists of int values, which can cause some rounding issues
  2. On each ACTION_MOVE event, you are adding the (potentially) rounded values, and changing the baseline (mPrevX & mPrevY) instead of calculating the absolute distance from where you first started dragging

I would store the current position of the tile when dragging starts (including offset from the cursor position), and then base all the movement calculations off of that point.

Upvotes: 1

Related Questions