0

ユーザーが長押しするポイントをマークしている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()など)を試しましたが、無駄でした。

手伝ってくれますか?

4

1 に答える 1

1

1 getImageMatrix() を使用

2 反転 - invert()

3 inverted.mapPoints() を使用する

于 2013-11-13T09:22:22.647 に答える