2012-12-19 5 views
9

Ich habe ein kleines Problem mit meiner App. Ich habe gerade Pinch-Zoom implementiert, aber wenn ich zu zoomen ziehe, skaliert das Bild nicht in der Mitte der 2 Punkte wie in den folgenden Bildern angezeigt. Bild 1 ist, wo meine Finger sind vor dem Einklemmen und Bild 2 ist zu zeigen, dass es nicht in der Mitte meiner Finger skaliert wurde, wie es sollte.Android SDK - Skalierung nicht im Zentrum der Berührung

Bild 1 vs Bild 2:
image1image2

ist hier mein Code:

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

Danke,

Jared

Antwort

10

In Ihrem ScaleListener Klasse, die Sie nur einstellen mScaleFactor so, in der Tat, Sie Bild wird in der Tat nicht Zoom um die Mitte von Ihnen Multi-Touch-Geste!

Zusätzlich müssen Sie mPosX und mPosY aktualisieren, um ein anderes Skalierungszentrum zu verwenden.

Für eine meiner eigenen Anwendungen, ich etwas wie folgt verwendet:

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

Grundsätzlich berechnet sie die relative Änderung des Ursprungs des Bildes durch

  1. die Herkunft Ihrer Multi Grabbing -touch Geste (getFocus())
  2. Berechnen der Differenz zwischen Ihrem Bildursprung (diffX und diffY)
  3. Anwendung des Skalierungsfaktors
  4. und den Ursprung des Bildes Aktualisierung durch die skalierte Differenz mit

Diese (noch) für meine Situation funktioniert. Ich weiß nicht, ob wir beide (d) die gleichen Koordinatensysteme verwenden, aber so etwas sollte Ihnen helfen, das Bild in der Mitte der Multi-Touch-Geste richtig zu skalieren.

1

Es hat mich sehr lange gedauert, bis das funktionierte .. aber danke für fast funktionierenden Code! Ich bin mir nicht sicher, ob ich nur herumspielen würde oder was, aber mit diesen Änderungen im Code habe ich meine Zoom-Arbeit bekommen, wie ich es wollte! Hoffentlich wird dies einige Zeit retten.

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; 

Zu Beginn scaleAtm = 1.

+0

Nein, wird es nicht. Weil dein Code fehlt. Was ist ScaleAtm? und wo benutzt du mTranslateMatrix? –

+0

Hey, ich benutze da etwas andere Skalierungsweise, weil ich alles nach dem Skalieren ziehen möchte. Sie können den Weg finden, den ich hier verwende http://stackoverflow.com/questions/12479859/view-with-horizontal-and-vertical-pan-drag-and-pinch-zoom/12497670#12497670 – niksi