2012-03-19 5 views
4

나는 만들고있는 안드로이드 애플 리케이션을위한 캔버스 좌표를 얻으려고합니다.안드로이드 - 핀치 줌 온 터치 이벤트 좌표

scalePoint.setX((int) detector.getFocusX()); 
scalePoint.setY((int) detector.getFocusY()); 

여기 내보기 클래스 내 소스 코드입니다 : 내가 (두 줄 다음) 규모의 초점 포인트를 사용하는 코드를 추가 할 때까지 잘 작동

package us.kniffin.Jigsaw; 

import android.app.AlertDialog; 
import android.content.Context; 
import android.content.DialogInterface; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Rect; 
import android.view.GestureDetector.SimpleOnGestureListener; 
import android.view.MotionEvent; 
import android.view.ScaleGestureDetector; 
import android.view.View; 

public class TestView extends View { 
    private float mLastTouchX; 
    private float mLastTouchY; 
    private float mPosX; 
    private float mPosY; 

    private Rect rect; 

    private float cX, cY; // circle coords 


    // Scaling objects 
    private ScaleGestureDetector mScaleDetector; 
    private float mScaleFactor = 1.f; 
    // The focus point for the scaling 
    private float scalePointX; 
    private float scalePointY; 


    public TestView(Context context) { 
     super(context); 

     mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) {  
     super.onDraw(canvas); 
     Paint p = new Paint(); 
     p.setColor(Color.RED); 

     rect = canvas.getClipBounds(); 

     canvas.save(); 
     canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY); 
     canvas.translate(mPosX, mPosY); 
     canvas.drawCircle(cX, cY, 10, p); 

     canvas.restore(); 

    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     // Let the ScaleGestureDetector inspect all events. 
     mScaleDetector.onTouchEvent(ev); 

     final int action = ev.getAction(); 


     switch(action & MotionEvent.ACTION_MASK) { 
     case MotionEvent.ACTION_DOWN: { 

      final float x = ev.getX()/mScaleFactor;// screen X position 
      final float y = ev.getY()/mScaleFactor;// screen Y position 

      cX = x - (rect.left * mScaleFactor) - mPosX; // canvas X 
      cY = y - (rect.top * mScaleFactor) - mPosY; // canvas Y 

      // Remember where we started 
      mLastTouchX = x; 
      mLastTouchY = y; 
      break; 
     } 
     case MotionEvent.ACTION_MOVE: { 
      final float x = ev.getX()/mScaleFactor; 
      final float y = ev.getY()/mScaleFactor; 
      cX = x - (rect.left * mScaleFactor) - mPosX; // canvas X 
      cY = y - (rect.top * mScaleFactor) - mPosY; // canvas Y 


      // Only move if the ScaleGestureDetector isn't processing a gesture. 
      if (!mScaleDetector.isInProgress()) { 
       final float dx = x - mLastTouchX; // change in X 
       final float dy = y - mLastTouchY; // change in Y 

       mPosX += dx; 
       mPosY += dy; 

       invalidate(); 
      } 

      mLastTouchX = x; 
      mLastTouchY = y; 

      break; 

     } 
     case MotionEvent.ACTION_UP: { 
      mLastTouchX = 0; 
      mLastTouchY = 0; 
      invalidate(); 
     } 
     } 
     return true; 
    } 

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) { 
      mScaleFactor *= detector.getScaleFactor(); 
      scalePointX = detector.getFocusX(); 
      scalePointY = detector.getFocusY(); 

      // Don't let the object get too small or too large. 
      mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f)); 

      invalidate(); 
      return true; 
     } 
    } 


} 

내가해야 할 일을 어떤 아이디어를 이 일을하려면?

업데이트

: 나는 같은 문제를 가지 서로 코드 샘플을 교체하지만,

업데이트 다시 필수로 단순화 : 문제는 확장 후 발생합니다. 크기를 조정하기 전에 좌표가 정확하지만 이후에 좌표가 오른쪽과 아래로 너무 멀리 떨어져 있습니다. 축소하는 것이 더 많을수록 더 많은 잘못을 겪게됩니다.

+0

동일한 효과를 나타내는 작은 프로그램을 만들 수 있다면 답을 얻는 것이 더 쉬울 수 있습니다. 행운을 빕니다! –

+0

좋습니다. 내가 할게. – dkniffin

+0

또 다른 제안 : 항상 100이나 항상 크거나 작은/무작위로 .. 어긋나거나, 도움이 될만한 것들을 조정해야하는 이유 (예 : 오류)를 정확히 설명해야합니다. – zapl

답변

8

하하! 성공! 거의 하루 종일 나를 데려 갔지만, 나는 그것을 추측하고 수표를내어 알아 냈다.

case MotionEvent.ACTION_DOWN: { 
      final float x = (ev.getX() - scalePointX)/mScaleFactor; 
      final float y = (ev.getY() - scalePointY)/mScaleFactor; 
      cX = x - mPosX + scalePointX; // canvas X 
      cY = y - mPosY + scalePointY; // canvas Y 
[snip] 
} 

을 그리고 매우 비슷한 일부 시행 착오 이후 뭔가를하고있는 동안 나는 최근이 문제에 온 ACTION_MOVE

+0

와우, 너의 노력은 내 친구에게 감사 하네. – yajnesh

1

번역, 축척, 회전 (등)을 사용할 때마다 캔버스의 행렬이 변경됩니다. 일반적으로이 행렬은 캔버스에있는 각 (x, y)를 알려주는데 사용됩니다. 캔버스를 만들 때 행렬은 단위 행렬입니다. (1) (1) (1) 그러나 이러한 변경 사항 중 하나를 수행 할 때마다이 행렬도 변경됩니다. 스케일링/회전하기 전에 올바른 좌표를 알고 싶다면 canvas.save()를 사용하고 스케일링 후에 canvas.restore()를 사용해야합니다.

+0

확인. 저장 및 복원을 사용하고 있으며 내 문제를 해결하지 못합니다. 이해할 수 있을지 모르겠다. 나는 그들을 잘못 사용하고 있는가? – dkniffin

0

에 대한 코드의 비슷한 비트 : 여기

내가 필요한 코드의 비트입니다 나는 인터넷 검색을 많이이 답변 ( https://stackoverflow.com/a/9945896/1131180) 적응 결국 :

(e는하는 MotionEvent 그래서 onTouch 또는 onLongPress에있을 것입니다이 코드를 사용하는 가장 좋은 장소를)

mClickCoords = new float[2]; 

//e is the motionevent that contains the screen touch we 
//want to translate into a canvas coordinate 
mClickCoords[0] = e.getX(); 
mClickCoords[1] = e.getY(); 

Matrix matrix = new Matrix(); 
matrix.set(getMatrix()); 

//this is where you apply any translations/scaling/rotation etc. 
//Typically you want to apply the same adjustments that you apply 
//in your onDraw(). 

matrix.preTranslate(mVirtualX, mVirtualY); 
matrix.preScale(mScaleFactor, mScaleFactor, mPivotX, mPivotY); 

// invert the matrix, creating the mapping from screen 
//coordinates to canvas coordinates 
matrix.invert(matrix); 

//apply the mapping 
matrix.mapPoints(mClickCoords); 

//mClickCoords[0] is the canvas x coordinate and 
//mClickCoords[1] is the y coordinate. 

여기에 적용 할 수있는 확실한 최적화가 있지만이 방법이 더 명확하다고 생각합니다.