10

먼저 원래 여기에 질문 후속 질문은, 응답 없음 아직 이었기 때문에, 나는 마침내 android-gesture-detectors잘못된 규모의 위치 안드로이드 캔버스에 확대 효과를 적용한 후 모든이의

를 사용하여 내 문제를 해결

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

변환을 적용하려면 수학 규칙을 이해해야합니다. 2 차원 및 3 차원 그래픽 모두에서 작동합니다. 즉, 변환 (T), 회전 (R), 스케일 (S) 행렬을 사용하여 변환을 적용하면 먼저 스케일 객체가 있고 (이 행렬 S로 좌표 xyz를 곱한 다음)) 그런 다음 T만큼 객체를 이동합니다. 회전을 적용하면 객체를 0으로 이동하고 비율을 조정 한 다음 기준점으로 되돌려 야합니다. 즉, 경우에 따라 눈금을 적용하기 전에 터치 좌표로 모든 좌표를 이동 (감소) 한 다음 곱하기로 눈금 행렬을 적용한 다음이 터치로 모든 위치를 증가시켜 이동해야합니다.

+0

코드 예제를 제공해 주시겠습니까? 앞에서 언급했듯이 이것은 후속 질문이므로 캔버스 크기 조정 및 확대/축소에 대한 자신 만의 아이디어를 줄 수 있습니다. –

2

다음은 내가 한 일입니다. 기본적으로 "이전"과 새로운 점의 차이점을 찾아야합니다.

@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; 
} 

차이를 만든 줄 것은 다음했다 ... 중요한 라인 하단으로 건너 뛰기 :

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

이 대답은 두 점 사이의 차이를 알아내는 것만 큼 간단했다 이미지 크기가 조정될 때마다 이미지 뷰를 번역합니다.

관련 문제