1

Being Android programming newbie I am trying to find out, if the user has touched a child (the yellow tile at the left in the picture below) at a custom View (source code: MyView.java):

Foto

For hitTesting I have written the following method:

private Drawable hitTest(int x, int y) {
    for (Drawable tile: mTiles) {
        Rect rect = tile.getBounds();
        if (rect.contains(x, y))
            return tile;
    }

    return null;
}

However I don't know, how to translate the MotionEvent coordinates, before passing them to the above method. I have tried many possible combinations, involving the mScale and mOffset properties of my custom View (I do not want to use View.scrollTo() and View.setScaleX() methods - but handle the offset and scale myself).

When I start randomly touching the screen, then I sometimes hit the tiles - so I see that my hitTest method is okay, but I just need to figure out the proper translation.

Do I miss something here, should I maybe add some translation between dp and real pixels?

public boolean onTouchEvent(MotionEvent e) {
    Log.d("onToucheEvent", "mScale=" + mScale +
            ", mOffsetX=" + mOffsetX +
            ", mOffsetY=" + mOffsetY +
            ", e.getX()=" + e.getX() +
            ", e.getY()=" + e.getY() +
            ", e.getRawX()=" + e.getRawX() +
            ", e.getRawY()=" + e.getRawY()
            );

    int x = (int) (e.getX() / mScale - mOffsetX);
    int y = (int) (e.getY() / mScale- mOffsetY);
    Drawable tile = hitTest(x, y);
    Log.d("onToucheEvent", "tile=" + tile);

    boolean retVal = mScaleDetector.onTouchEvent(e);
    retVal = mGestureDetector.onTouchEvent(e) || retVal;
    return retVal || super.onTouchEvent(e);
}

UPDATE: Following pskink's advice (thanks) I am trying to use Matrix and have change my custom MyView.java to:

protected void onDraw(Canvas canvas) {
    mMatrix.reset();
    mMatrix.setTranslate(mOffsetX, mOffsetY);
    mMatrix.postScale(mScale, mScale);
    canvas.setMatrix(mMatrix);

    mGameBoard.draw(canvas);

    for (Drawable tile: mTiles) {
        tile.draw(canvas);
    }
}

public boolean onTouchEvent(MotionEvent e) {
    float[] point = new float[] {e.getX(), e.getY()};

    Matrix inverse = new Matrix();
    mMatrix.invert(inverse);
    inverse.mapPoints(point);

    float density = getResources().getDisplayMetrics().density;
    point[0] /= density;
    point[1] /= density;

    Drawable tile = hitTest((int) point[0], (int) point[1]);
    Log.d("onToucheEvent", "tile=" + tile);
}

But unfortunately my hitTest() does not find any touched tiles.

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
  • 1
    Alex, with Matrix you will do that in one simple call Matrix.mapPoints(), see method "contains" in my answer http://stackoverflow.com/questions/21633545/android-imageview-scaling-and-translating-issue – pskink Nov 01 '14 at 11:51
  • So in my [custom View](https://github.com/afarber/android-newbie/blob/master/TestScroll2/src/de/afarber/testscroll2/MyView.java) should I call `getMatrix().invert(getMatrix())` and then `mapPoints()` on the array with touch event coordinates? What will it give me, the coordinates in which system? – Alexander Farber Nov 01 '14 at 22:11
  • 1
    first change your code so that onDraw doesnt use Canvas.scale und translate but rather Canvas.concat, then having right Matrix you will figure it out in a few minutes when you Log.d the input and output array – pskink Nov 01 '14 at 22:38
  • +1 thanks - I have updated my code and question, still can't hit the tiles... – Alexander Farber Nov 02 '14 at 21:52
  • 1
    see http://pastebin.com/MfFudGju, look for comments with "pskink" inside – pskink Nov 03 '14 at 09:12
  • +1 thanks. I have change all code in [MyView.java](https://github.com/afarber/android-newbie/blob/master/TestScroll2/src/de/afarber/testscroll2/MyView.java) to use `Matrix` as you recommended - and the scroll and fling work. But scaling with pinch gesture causes the scaled image to jump, can you maybe spot what is wrong there? – Alexander Farber Nov 03 '14 at 18:44
  • 1
    this is probably because setScale/setRotate/setTranslate resets the other values e.g. if your Matrix is scaled to 4,4 and translated to 100,100 and then you call setScale(5, 5) your translation (and rotation if any) is reset to 0 – pskink Nov 03 '14 at 19:13
  • That is a very insightful comment - I understand now the current jerkiness in my app (when scaling or after flinging...) So I have to read the old values with `getValues` and then call `postXXX`- I wonder if there is a more comfortable way... – Alexander Farber Nov 03 '14 at 21:09

0 Answers0