ユーザーが長押しするポイントをマークしているAndroidアプリを試しています。タッチ センシティブな画像ビューについては、ここのコードのほとんどを使用しまし た 。 .com/training/gestures/scale.html と、stackoverflow のさまざまな投稿からのいくつかの提案。これはタッチ画像ビューのコードです:
public class SimpleImageView extends ImageView implements OnTouchListener,OnGestureListener {
public HashMap<meeCoordinates, Integer> plotPointsMap = new HashMap<meeCoordinates, Integer>();
private float mPosX = 0f;
private float mPosY = 0f;
private boolean didLongPress = false;
private float mLastTouchX;
private float mLastTouchY;
private float magicX;
private float magicY;
private static final int INVALID_POINTER_ID = -1;
Context context;
Canvas canvas;
private GestureDetector gestureScanner;
int deviceWidth, deviceHeight;
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
String savedItemClicked;
private int mActivePointerId = INVALID_POINTER_ID;
public SimpleTouchImageView(Context ctx) {
// The ‘active pointer’ is the one currently moving our object.
this(ctx, null, 0);
this.context = ctx;
}
public SimpleTouchImageView(Context ctx, AttributeSet attrs) {
this(ctx, attrs, 0);
this.context = ctx;
}
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
public SimpleTouchImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Create our ScaleGestureDetector
if (!this.isInEditMode()) {
mScaleDetector = new ScaleGestureDetector(context,new ScaleListener());
}
gestureScanner = new GestureDetector(context, this);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mScaleDetector != null) {
mScaleDetector.onTouchEvent(ev);
}
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
Log.d(TAG, "onTouchEvent MotionEvent.ACTION_DOWN");
final float x = ev.getX();
final float y = ev.getY();
// Set them to the X, Y at the beginning of the touch event
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
// _handler.postDelayed(_longPressed, LONG_PRESS_TIME);
break;
}
case MotionEvent.ACTION_MOVE: {
// _handler.removeCallbacks(_longPressed);
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
if (mScaleDetector != null) {
if (!mScaleDetector.isInProgress()) {
// Calculate the distance moved
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
// Move the object
mPosX += dx;
mPosY += dy;
// Remember this touch position for the next move event
mLastTouchX = x;
mLastTouchY = y;
invalidate();
}
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
// _handler.removeCallbacks(_longPressed);
mActivePointerId = INVALID_POINTER_ID;
// Calculate the Actual X & Y
Drawable drawable = this.getDrawable();
Rect imageBounds = drawable.getBounds();
int intrinsicHeight = this.getDrawable().getIntrinsicHeight();
int intrinsicWidth = this.getDrawable().getIntrinsicWidth();
int imageOffsetX = (int) (ev.getX() - imageBounds.left);
int imageOffsetY = (int) (ev.getY() - imageBounds.top);
float[] f = newfloat[9];
this.getImageMatrix().getValues(f);
final float scaleX = f[Matrix.MSCALE_X];
final float scaleY = f[Matrix.MSCALE_Y];
final int actualWd = Math.round(intrinsicWidth * mScaleFactor);
final int actualHt = Math.round(intrinsicHeight * mScaleFactor);
// CALCULATE THE X,Y COORDINATES CORRESPONDING TO THE POINT OF TOUCH
// IN THE ACTUAL IMAGE,
magicX = ((ev.getX() + (-1 * mPosX)) / mScaleFactor);
magicY = ((ev.getY() + (-1 * mPosY)) / mScaleFactor);
mLastTouchX = ev.getX();
mLastTouchY = ev.getY();
if (didLongPress == true) {
// STORE THE Point where user did long press IN AN ARRAY
plotPointsMap.put ( coordinates, marker );
invalidate();
didLongPress = false;
}
break;
}
case MotionEvent.ACTION_CANCEL: {
// _handler.removeCallbacks(_longPressed);
Log.d(TAG, "onTouchEvent MotionEvent.ACTION_CANCEL");
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// _handler.removeCallbacks(_longPressed);
Log.d(TAG, "onTouchEvent MotionEvent.ACTION_POINTER_UP");
break;
}
}
// return true;
return gestureScanner.onTouchEvent(ev);
}
/** Determine the space between the first two fingers */
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
}
@Override
public void onDraw(Canvas canvas) {
WindowManager wm = (WindowManager) this.context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
deviceWidth = metrics.widthPixels;
deviceHeight = metrics.heightPixels;
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint);
if (this.getDrawable() != null) {
canvas.save();
canvas.translate(mPosX, mPosY);
Matrix matrix = new Matrix();
matrix.postScale(mScaleFactor, mScaleFactor, pivotPointX,pivotPointY);
canvas.drawBitmap(((BitmapDrawable) this.getDrawable()).getBitmap(), matrix,null);
// ---add the marker---
if ((plotPointsMap != null) && (plotPointsMap.size() > 0)) {
for (int index = 0; index < plotPointsMap.size(); index++) {
Set<MyCoordinates> setCoordinates = plotPointsMap.keySet();
if ((setCoordinates != null) && (setCoordinates.size() > 0)) {
Iterator<MyCoordinates> setIterator =setCoordinates.iterator();
if (setIterator != null) {
while (setIterator.hasNext()) {
MyCoordinates coordinates = setIterator.next();
int resource = plotPointsMap.get(coordinates).intValue();
int resourceId = R.drawable.location_marker;
Bitmap marker = BitmapFactory.decodeResource(getResources(), resourceId);
float xCoordinate = coordinates.getCoordinateX();
float yCoordinate = coordinates.getCoordinateY();
canvas.drawBitmap(marker, xCoordinate * mScaleFactor, yCoordinate * mScaleFactor, null);
}
}
}
}
}
canvas.restore();
}
}
@Override
public void setImageDrawable(Drawable drawable) {
// Constrain to given size but keep aspect ratio
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
mLastTouchX = mPosX = 0;
mLastTouchY = mPosY = 0;
mScaleFactor = Math.min((float) getLayoutParams().width/ width, (float) getLayoutParams().height/ height);
pivotPointX = ((float) getLayoutParams().width - (int) (width * mScaleFactor)) / 2;
pivotPointY = ((float) getLayoutParams().height - (int) (height * mScaleFactor)) / 2;
super.setImageDrawable(drawable);
}
float pivotPointX = 0f;
float pivotPointY = 0f;
...
...
}
問題 今のところ、スケーリングは脇に置きましょう。たとえば、画像は実際のサイズで読み込まれます。ユーザーがタッチしたポイントが正しく記録されます。たとえば、ユーザーが x=120、y=50 の (120, 50) をタッチすると、(120, 50) として正しく検出されます。ポイントを配列に保存し、各ポイントでマーカーを再描画しています
public void onDraw(Canvas canvas)
問題は、マーカーがポイント (onDraw(canvas) 内で印刷している) に描画されると、マーカーが実際のポイントから約 30px 離れて描画されることです。つまり、実際の (x,y) が (120,50) の場合、マーカー イメージは (150,80) 付近に描画されます。常にこの 30px の差があります。どうしてこれなの?過去 2 週間無駄に以来、これについて頭を悩ませています。誰か助けてくれませんか?
これはタッチ ポイントを青色で示した画像です (「US」の文字「S」の上)。タッチ ポイントから黒いマーカーが引き出されていることがわかります。
EDIT 画像をパンすると、inverse.mapPoints()は画面から離れた画像のオフセットを考慮しません。例えばこちらがアプリ起動時の画像で、これが読み込まれた画像です
ユーザーがパンすると、画像は次のように画面の端の左側に移動する可能性があります。
そんな時、inverse.mapPoints()は画面の端からの値しか返さないのですが、元画像の端からの値が欲しいです。どうすればいいのですか?私はグーグルを試し、stackoverflowで与えられたいくつかのこと(getTop()、およびgetLocationOnscreen()など)を試しましたが、無駄でした。
手伝ってくれますか?