2012-12-19 103 views
9

我的應用程序有點問題。我剛剛實施了縮放縮放,但是當我縮小變焦時,圖像不會縮放在下面圖像中顯示的2個點的中心。圖像1是我的手指在捏之前的位置,圖像2是要顯示它沒有縮放到我手指的中心位置。Android SDK - 在觸摸中心不縮放

圖片1對圖2:
image1image2

這裏是我的代碼:

 package com.jpiionefourone.guitarimage; 

    import android.content.Context; 
    import android.graphics.Canvas; 
    import android.graphics.drawable.Drawable; 
    import android.util.AttributeSet; 
    import android.view.MotionEvent; 
    import android.view.ScaleGestureDetector; 
    import android.view.View; 

    public class MultiTouchView extends View { 
     private Drawable mIcon; 
     private float mPosX; 
     private float mPosY; 

     private float mLastTouchX; 
     private float mLastTouchY; 

     private static final int INVALID_POINTER_ID = -1; 

     // The ‘active pointer’ is the one currently moving our object. 
     private int mActivePointerId = INVALID_POINTER_ID; 

     private ScaleGestureDetector mScaleDetector; 
     private float mScaleFactor = 1.f; 


     public MultiTouchView(Context context) { 
      this(context, null, 0); 
     } 

     public MultiTouchView(Context context, AttributeSet attrs) { 
      this(context, attrs, 0); 
     } 

     public MultiTouchView(Context context, AttributeSet attrs, int defStyle) { 
      super(context, attrs, defStyle); 
      mIcon = context.getResources().getDrawable(R.drawable.guitar); 
      mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight()); 

      // Create our ScaleGestureDetector 
      mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 

     } 

     @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(); 
       final float y = ev.getY(); 

       mLastTouchX = x; 
       mLastTouchY = y; 
       mActivePointerId = ev.getPointerId(0); 
       break; 
      } 

      case MotionEvent.ACTION_MOVE: { 
       final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
       final float x = ev.getX(pointerIndex); 
       final float y = ev.getY(pointerIndex); 

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

        mPosX += dx; 
        mPosY += dy; 

        invalidate(); 
       } 

       mLastTouchX = x; 
       mLastTouchY = y; 

       break; 
      } 

      case MotionEvent.ACTION_UP: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_CANCEL: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_POINTER_UP: { 
       final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
         >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
       final int pointerId = ev.getPointerId(pointerIndex); 
       if (pointerId == mActivePointerId) { 
        // This was our active pointer going up. Choose a new 
        // active pointer and adjust accordingly. 
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
        mLastTouchX = ev.getX(newPointerIndex); 
        mLastTouchY = ev.getY(newPointerIndex); 
        mActivePointerId = ev.getPointerId(newPointerIndex); 
       } 
       break; 
      } 
      } 

      return true; 
     } 

     @Override 
     public void onDraw(Canvas canvas) { 
      super.onDraw(canvas); 

      canvas.save(); 
      canvas.translate(mPosX, mPosY); 
      canvas.scale(mScaleFactor, mScaleFactor); 
      mIcon.draw(canvas); 
      canvas.restore(); 
     } 

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

感謝,

賈裏德

回答

10

在你ScaleListener類,你只能調整mScaleFactor所以,確實,你的圖像確實會不是放大你的多點觸摸手勢的中心!

此外,您需要更新mPosXmPosY以使用不同的縮放中心。

對於我自己的應用程序之一,我用的是這樣的:

final float scale = detector.getScaleFactor(); 
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor * scale, 5.0f)); 

if (mScaleFactor < 5f) { 
    // 1 Grabbing 
    final float centerX = detector.getFocusX(); 
    final float centerY = detector.getFocusY(); 
    // 2 Calculating difference 
    float diffX = centerX - mPosX; 
    float diffY = centerY - mPosY; 
    // 3 Scaling difference 
    diffX = diffX * scale - diffX; 
    diffY = diffY * scale - diffY; 
    // 4 Updating image origin 
    mPosX -= diffX; 
    mPosY -= diffY; 
} 

基本上,它計算出

  1. 抓住你多起源圖像起源的相對變化觸摸手勢(getFocus()
  2. 計算圖像原點之間的差異(diffXdiffY
  3. 應用比例因子
  4. ,通過使用比例差異

這(仍)適用於我的情況更新圖像的起源。我不知道我們是否都使用(d)相同的座標系,但像這樣的東西應該可以幫助您正確縮放多點觸控手勢中心的圖像。

1

我花了很長時間纔得到這個工作..但是,感謝幾乎工作的代碼!我不知道是我只是搞亂了或者只是在代碼中進行了這些更改,我得到了我想要的縮放工作!希望這會讓某些人安全。

mScaleFactor *= detector.getScaleFactor(); 
mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 3.0f)); 
scale = mScaleFactor/scaleAtm 


mTranslateMatrix.preTranslate(diffX, diffY); 
mTranslateMatrix.invert(mTranslateMatrixInverse); 
mPosX += diffX; 
mPosY += diffY; 
scaleAtm = mScaleFactor; 

起初scaleAtm = 1

+0

不,不會。因爲你的代碼丟失了。什麼是scaleAtm?你在哪裏使用mTranslateMatrix? –

+0

嘿,即時通訊使用有點不同縮放方式,因爲我想能夠在縮放後拖動所有內容。你可以找到我在這裏使用的方式 http://stackoverflow.com/questions/12479859/view-with-horizo​​ntal-and-vertical-pan-drag-and-pinch-zoom/12497670#12497670 – niksi