Use GestureDetector to handle touch events

This commit is contained in:
Manuel Fuhr 2021-10-20 07:59:04 +02:00
parent b8496ffe5e
commit 712bff8459

View file

@ -1,5 +1,6 @@
package btools.routingapp; package btools.routingapp;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -9,7 +10,9 @@ import android.graphics.Color;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View; import android.view.View;
import java.io.File; import java.io.File;
@ -24,25 +27,25 @@ public class BInstallerView extends View {
public static final int MASK_DELETED_RD5 = 2; public static final int MASK_DELETED_RD5 = 2;
public static final int MASK_INSTALLED_RD5 = 4; public static final int MASK_INSTALLED_RD5 = 4;
public static final int MASK_CURRENT_RD5 = 8; public static final int MASK_CURRENT_RD5 = 8;
private static final float SCALE_GRID_VISIBLE = 3;
private final Bitmap bmp;
private final float[] testVector = new float[2];
private final int[] tileStatus;
private final File segmentDir; private final File segmentDir;
private final Matrix mat; private final Matrix mat;
private final Bitmap bmp;
private final int[] tileStatus;
private final float[] testVector = new float[2];
private final Matrix matText; private final Matrix matText;
private final GestureDetector mGestureDetector;
private final ScaleGestureDetector mScaleGestureDetector;
Paint pnt_1 = new Paint(); Paint pnt_1 = new Paint();
Paint pnt_2 = new Paint(); Paint pnt_2 = new Paint();
Paint paint = new Paint(); Paint paint = new Paint();
int btnh = 40; int btnh = 40;
int btnw = 160; int btnw = 160;
float tx, ty;
private int imgwOrig; private int imgwOrig;
private int imghOrig; private int imghOrig;
private float scaleOrig; private float scaleOrig;
private int imgw; private int imgw;
private int imgh; private int imgh;
private float lastDownX;
private float lastDownY;
private float viewscale; private float viewscale;
private boolean tilesVisible = false; private boolean tilesVisible = false;
private long availableSize; private long availableSize;
@ -69,6 +72,21 @@ public class BInstallerView extends View {
tileStatus = new int[72 * 36]; tileStatus = new int[72 * 36];
matText = new Matrix(); matText = new Matrix();
mat = new Matrix(); mat = new Matrix();
mGestureDetector = new GestureDetector(context, new GestureListener());
mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener());
}
private void setRatio(float ratio, float focusX, float focusY) {
mat.postScale(ratio, ratio, focusX, focusY);
fitBounds();
tilesVisible = currentScale() >= SCALE_GRID_VISIBLE;
invalidate();
}
private void setScale(float scale, float focusX, float focusY) {
float ratio = scale / currentScale();
setRatio(ratio, focusX, focusY);
} }
public void setAvailableSize(long availableSize) { public void setAvailableSize(long availableSize) {
@ -142,9 +160,9 @@ public class BInstallerView extends View {
imgh = (int) (imghOrig / scaleOrig); imgh = (int) (imghOrig / scaleOrig);
float scaleX = imgwOrig / ((float) bmp.getWidth()); float scaleX = imgwOrig / ((float) bmp.getWidth());
float scaley = imghOrig / ((float) bmp.getHeight()); float scaleY = imghOrig / ((float) bmp.getHeight());
viewscale = Math.min(scaleX, scaley); viewscale = Math.min(scaleX, scaleY);
mat.postScale(viewscale, viewscale); mat.postScale(viewscale, viewscale);
tilesVisible = false; tilesVisible = false;
@ -260,120 +278,55 @@ public class BInstallerView extends View {
} }
} }
private void fitBounds() {
float[] srcPoints = new float[]{
0, 0,
bmp.getWidth(), bmp.getHeight()
};
float[] dstPoints = new float[srcPoints.length];
float transX = 0;
float transY = 0;
mat.mapPoints(dstPoints, srcPoints);
if (dstPoints[0] > 0) {
transX = -dstPoints[0];
} else if (dstPoints[2] < getWidth()) {
transX = getWidth() - dstPoints[2];
}
if (dstPoints[1] > 0) {
transY = -dstPoints[1];
} else if (dstPoints[3] < getHeight()) {
transY = getHeight() - dstPoints[3];
}
if (transX != 0 || transY != 0) {
mat.postTranslate(transX, transY);
}
}
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
boolean retVal = mScaleGestureDetector.onTouchEvent(event);
// get masked (not specific to a pointer) action retVal = mGestureDetector.onTouchEvent(event) || retVal;
int maskedAction = event.getActionMasked(); return retVal || super.onTouchEvent(event);
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
lastDownX = event.getX();
lastDownY = event.getY();
break;
}
case MotionEvent.ACTION_MOVE: { // a pointer was moved
int np = event.getPointerCount();
int nh = event.getHistorySize();
if (nh == 0) break;
float x0 = event.getX(0);
float y0 = event.getY(0);
float hx0 = event.getHistoricalX(0, 0);
float hy0 = event.getHistoricalY(0, 0);
if (np > 1) // multi-touch
{
float x1 = event.getX(1);
float y1 = event.getY(1);
float hx1 = event.getHistoricalX(1, 0);
float hy1 = event.getHistoricalY(1, 0);
float r = (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
float hr = (float) Math.sqrt((hx1 - hx0) * (hx1 - hx0) + (hy1 - hy0) * (hy1 - hy0));
if (hr > 0.) {
float ratio = r / hr;
float mx = (x1 + x0) / 2.f;
float my = (y1 + y0) / 2.f;
float scale = currentScale();
float newscale = scale * ratio;
if (newscale > 10.f) ratio *= (10.f / newscale);
if (newscale < 0.5f) ratio *= (0.5f / newscale);
mat.postScale(ratio, ratio, mx, my);
mat.postScale(ratio, ratio, mx, my);
boolean tilesv = currentScale() >= 3.f;
if (tilesVisible && !tilesv) {
clearAllTilesStatus(MASK_SELECTED_RD5 | MASK_DELETED_RD5);
}
tilesVisible = tilesv;
} }
break; class GestureListener extends GestureDetector.SimpleOnGestureListener {
}
mat.postTranslate(x0 - hx0, y0 - hy0);
break; @Override
} public boolean onSingleTapConfirmed(MotionEvent e) {
case MotionEvent.ACTION_UP: // Download Button
if ((delTiles > 0 || rd5Tiles >= 0) && e.getX() > imgwOrig - btnw * scaleOrig && e.getY() > imghOrig - btnh * scaleOrig) {
long downTime = event.getEventTime() - event.getDownTime();
if (downTime < 5 || downTime > 500) {
break;
}
if (Math.abs(lastDownX - event.getX()) > 10 || Math.abs(lastDownY - event.getY()) > 10) {
break;
}
// download button?
if ((delTiles > 0 || rd5Tiles >= 0) && event.getX() > imgwOrig - btnw * scaleOrig && event.getY() > imghOrig - btnh * scaleOrig) {
if (rd5Tiles == 0) {
for (int ix = 0; ix < 72; ix++) {
for (int iy = 0; iy < 36; iy++) {
int tidx = gridPos2Tileindex(ix, iy);
if (tidx != -1) {
if ((tileStatus[tidx] & MASK_INSTALLED_RD5) != 0) {
tileStatus[tidx] |= MASK_SELECTED_RD5;
}
}
}
}
}
if (mOnClickListener != null) { if (mOnClickListener != null) {
mOnClickListener.onClick(null); mOnClickListener.onClick(null);
} }
invalidate(); invalidate();
break; return true;
}
if (!tilesVisible) {
float scale = currentScale();
if (scale > 0f && scale < 5f) {
float ratio = 5f / scale;
mat.postScale(ratio, ratio, event.getX(), event.getY());
tilesVisible = true;
}
break;
} }
if (tilesVisible) {
Matrix imat = new Matrix(); Matrix imat = new Matrix();
if (mat.invert(imat)) { if (mat.invert(imat)) {
float[] touchpoint = new float[2]; float[] touchpoint = {e.getX(), e.getY()};
touchpoint[0] = event.getX();
touchpoint[1] = event.getY();
imat.mapPoints(touchpoint); imat.mapPoints(touchpoint);
int tidx = tileIndex(touchpoint[0], touchpoint[1]); int tidx = tileIndex(touchpoint[0], touchpoint[1]);
@ -389,23 +342,52 @@ public class BInstallerView extends View {
tileStatus[tidx] ^= MASK_SELECTED_RD5; tileStatus[tidx] ^= MASK_SELECTED_RD5;
} }
} }
tx = touchpoint[0];
ty = touchpoint[1];
}
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
// TODO use data
break;
}
} }
invalidate(); invalidate();
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (!tilesVisible) {
setScale(5, e.getX(), e.getY());
} else {
setScale(1, e.getX(), e.getY());
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
mat.postTranslate(-distanceX, -distanceY);
fitBounds();
invalidate();
return true;
}
}
class ScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
return true;
}
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
float focusX = scaleGestureDetector.getFocusX();
float focusY = scaleGestureDetector.getFocusY();
float ratio = scaleGestureDetector.getScaleFactor();
setRatio(ratio, focusX, focusY);
return true; return true;
} }
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
}
}
} }