10

まず、もともとここに尋ねたフォローアップの質問は、応答なしまだあったので、私は最終的にandroid-gesture-detectors間違ったスケール位置Androidのキャンバス上のズーム効果を適用した後、このすべての

を使用して、私の問題を解決し

Pan, Zoom and Scale a custom View for Canvas drawing in Android私が見つけたズーム/スケールジェスチャーを適用した後、キャンバスの描画座標は、(ズームを適用する前の)古い位置を指し示しており、まったく同じタッチ座標に描画していません。基本的には、キャンバスの拡大縮小やドラッグ後に正しいキャンバス座標を取得できません。ズーミング前

enter image description here

タッチポイントをズームアウトした後、前の位置に描画されます。されているMoveGestureDetector()ScaleGestureDetector() & RotateGestureDetector():私は

enter image description here

、それが現在のタッチ位置に描画するサンプルコード、

public class DrawingView extends View { 

    private void setupDrawing() { 

     mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); 

     mgd = new MoveGestureDetector(ctx, mgl); 
     sgd = new ScaleGestureDetector(ctx, sgl); 
     rgd = new RotateGestureDetector(ctx, rgl); 

} 

class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) { 
      mScaleFactor *= detector.getScaleFactor(); 
      // Don't let the object get too small or too large. 
      mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); 
      invalidate(); 
      return true; 
     } 
    } 

    MoveGestureDetector.SimpleOnMoveGestureListener mgl = new MoveGestureDetector.SimpleOnMoveGestureListener() { 
     @Override 
     public boolean onMove(MoveGestureDetector detector) { 
      PointF delta = detector.getFocusDelta(); 
      matrix.postTranslate(delta.x, delta.y); 
      invalidate(); 
      return true; 
     } 
    }; 

    ScaleGestureDetector.SimpleOnScaleGestureListener sgl = new ScaleGestureDetector.SimpleOnScaleGestureListener() { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) { 
      float scale = detector.getScaleFactor(); 
      matrix.postScale(scale, scale, detector.getFocusX(), detector.getFocusY()); 
      invalidate(); 
      return true; 
     } 
    }; 

    RotateGestureDetector.SimpleOnRotateGestureListener rgl = new RotateGestureDetector.SimpleOnRotateGestureListener() { 
     @Override 
     public boolean onRotate(RotateGestureDetector detector) { 
      matrix.postRotate(-detector.getRotationDegreesDelta(), detector.getFocusX(), detector.getFocusY()); 
      invalidate(); 
      return true; 
     } 
    }; 

    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     //view given size 
     super.onSizeChanged(w, h, oldw, oldh); 
     canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
     drawCanvas = new Canvas(canvasBitmap); 
    } 

    private void touch_start(float x, float y) { 
     undonePaths.clear(); 
     drawPath.reset(); 
     drawPath.moveTo(x, y); 
     mX = x; 
     mY = y; 
    } 

    private void touch_move(float x, float y, float x2, float y2) { 
     float dx = Math.abs(x - mX); 
     float dy = Math.abs(y - mY); 
     if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { 
      /* QUad to curves using a quadratic line (basically an ellipse of some sort). 
      LineTo is a straight line. QuadTo will smooth out jaggedies where they turn. 
      */ 
      drawPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); 
      mX = x; 
      mY = y; 
     } 

    } 

    private void touch_up() { 

      drawPath.lineTo(mX, mY); 
      // commit the path to our offscreen 
      drawCanvas.drawPath(drawPath, drawPaint); 
      // kill this so we don't double draw 
      paths.add(drawPath); 
      drawPath = new Path(); 
      drawPath.reset(); 
      invalidate(); 
    } 

@Override 
    public boolean onTouchEvent(MotionEvent event) { 

     if (isZoomable) { 
      mgd.onTouchEvent(event); 
      sgd.onTouchEvent(event); 
      rgd.onTouchEvent(event); 
     } 

     if (!isTouchable) { 
      return super.onTouchEvent(event); 
     } else { 
      //detect user touch 
      float x = event.getX(); 
      float y = event.getY(); 

      switch (event.getAction() & MotionEvent.ACTION_MASK) { 

       case MotionEvent.ACTION_DOWN: 
        if (!isZoomable) { 
         touch_start(x, y); 
        } 
        invalidate(); 
        break; 

       case MotionEvent.ACTION_MOVE: 
        if (!isZoomable) { 
         //mPositions.add(new Vector2(x - mBitmapBrushDimensions.x/2, y - mBitmapBrushDimensions.y/2)); 
         if (isCustomBrush && mBitmapBrushDimensions != null) { 
          mPositions = new Vector2(x - mBitmapBrushDimensions.x/2, y - mBitmapBrushDimensions.y/2); 
          touch_move(x, y, x - mBitmapBrushDimensions.x/2, y - mBitmapBrushDimensions.y/2); 
         } else { 
          touch_move(x, y, 0, 0); 
         } 
        } 
        invalidate(); 
        break; 

       case MotionEvent.ACTION_UP: 
        if (!isZoomable) { 
         touch_up(); 
        } 
        invalidate(); 
        break; 
      } 
      mScaleDetector.onTouchEvent(event); 
      return true; 
     } 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     canvas.save(); 

     canvas.setMatrix(matrix); 

     for (Path p : paths) { 
       canvas.drawPath(p, drawPaint); 
       drawPaint.setColor(selectedColor); 
       drawPaint.setStrokeWidth(brushSize); 
       canvas.drawPath(drawPath, drawPaint); 
     } 
     canvas.restore(); 
    } 
} 

PS android-gesture-detectorsから継承したカスタムクラス

答えて

1

変換を適用するには、数学のルールを理解する必要があります。これは2dimと3次元グラフィックスの両方で機能します。 つまり、変換(T)、回転(R)、スケール(S)行列を使用して変換を適用すると、最初にスケールオブジェクトがあり(この行列Sで座標xyzを掛けます)、次に回転します)次に、Tでオブジェクトをシフトします。 したがって、ある点に回転を適用すると、オブジェクトをゼロに移動して基準点に戻す必要があります。 つまり、スケールを適用する前に、すべての座標をタッチ位置でシフト(減少)してから、スケールマトリックスを乗法で適用し、次にこのタッチによってすべての位置を増加させてシフトする必要があります。

+0

コード例を教えてください。前に説明したように、これはフォローアップの質問ですので、キャンバスの拡大/縮小について独自の考えを与えることができます。 –

2

ここに私がしたことがあります。基本的に、あなたは "古い"と新しいポイントの違いを見つけなければなりません。答えは2点間の差異を考え出すと同じくらい簡単だった

float xDiff = initialFocalPoints[0] - currentFocalPoints[0]; 
float yDiff = initialFocalPoints[1] - currentFocalPoints[1]; 
transformMatrix.postTranslate(xDiff, yDiff); 

と:違いを作っ

@Override 
public boolean onScale(ScaleGestureDetector detector) { 

    scaleFactor *= detector.getScaleFactor(); 

    float xDiff = initialFocalPoints[0] - currentFocalPoints[0]; 
    float yDiff = initialFocalPoints[1] - currentFocalPoints[1]; 

    transformMatrix.setScale(scaleFactor, scaleFactor, 
           currentFocalPoints[0], currentFocalPoints[1]); 
    transformMatrix.postTranslate(xDiff, yDiff);  
    child.setImageMatrix(transformMatrix); 

    return true; 
} 

@Override 
public boolean onScaleBegin(ScaleGestureDetector detector){ 

    float startX = detector.getFocusX() + getScrollX(); 
    float startY = detector.getFocusY() + getScrollY(); 

    initialFocalPoints = new float[]{startX, startY}; 

    if(transformMatrix.invert(inverseTransformMatrix)) 
    inverseTransformMatrix.mapPoints(currentFocalPoints, initialFocalPoints); 
    return true; 
} 

行は、以下のた...重要なラインの下にスキップイメージが拡大縮小されるたびにイメージビューを翻訳します。

関連する問題