2012-12-19 19 views
9

Ho un piccolo problema con la mia app. Ho appena implementato lo zoom con pizzico, ma quando pizzico per ingrandire, l'immagine non si scala al centro dei 2 punti come mostrato nelle immagini sottostanti. L'immagine 1 è dove le mie dita sono prima di pizzicare e l'immagine 2 deve mostrare che non è stata ridimensionata al centro delle dita come dovrebbe.Android SDK - Non in scala al centro del tocco

Immagine 1 vs Immagine 2:
image1image2

Ecco il mio codice:

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

Grazie,

Jared

risposta

10

Nella tua ScaleListener classe di regolare solo mScaleFactor così, infatti, l'immagine sarà effettivamente non zoom intorno al centro del tuo gesto multi-touch!

Inoltre, è necessario aggiornare mPosX e mPosY per utilizzare un diverso centro di ridimensionamento.

Per una delle mie applicazioni, ho usato qualcosa di simile:

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

Fondamentalmente, si calcola la variazione relativa delle origini della vostra immagine da

  1. afferrando l'origine del vostro multi -touch gesture (getFocus())
  2. calcolo della differenza tra l'origine dell'immagine (diffX e diffY)
  3. applicando il fattore di scala
  4. e aggiornare l'origine dell'immagine utilizzando la differenza in scala

questo (ancora) funziona per la mia situazione. Non so se entrambi usiamo (d) gli stessi sistemi di coordinate, ma qualcosa del genere dovrebbe aiutarti a ridimensionare correttamente l'immagine al centro del gesto multi-touch.

1

Mi ci è voluto molto tempo per farlo funzionare .. comunque grazie per il codice quasi funzionante! Non sono sicuro che stavo solo scherzando o cosa, ma con questo cambiamento di codice ho ottenuto il mio lavoro di zoom come volevo! Spero che questo sarà sicuro tempo per qualcuno.

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; 

All'inizio scaleAtm = 1.

+0

No, non lo farà. Perché manca il tuo codice. che cos'è scaleAtm? e dove usi mTranslateMatrix? –

+0

Ehi, sto usando un modo di scalare leggermente diverso perché voglio essere in grado di trascinare tutto dopo il ridimensionamento. Puoi trovare il modo in cui sto usando qui http://stackoverflow.com/questions/12479859/view-with-horizontal-and-vertical-pan-drag-and-pinch-zoom/12497670#12497670 – niksi

Problemi correlati