SDK de Android: no escala en el centro del tacto

Tengo un pequeño problema con mi aplicación. Acabo de implementar pinch zoom, pero cuando pellizco para hacer zoom, la imagen no escala en el centro de los 2 puntos como se muestra en las imágenes de abajo. Imagen 1 es donde mis dedos son antes de pellizcar y la imagen 2 es mostrar que no ha escalado en el centro de mis dedos como debería.

Imagen 1 vs Imagen 2:
Image1Image2

Aquí está mi código:

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

Gracias,

Jared

En su clase ScaleListener sólo ajusta mScaleFactor así que, de hecho, la imagen de hecho no zoom alrededor del centro de su gesto multi-touch!

Además, es necesario actualizar mPosX y mPosY para utilizar un centro diferente de escalado.

Para una de mis propias aplicaciones, he usado algo como esto:

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

Básicamente, calcula el cambio relativo del origen de la imagen por

  1. Agarrando el origen de su gesto multi-touch ( getFocus() )
  2. Calculando la diferencia entre el origen de la imagen ( diffX y diffY )
  3. Aplicando el factor de escala
  4. Y actualizar el origen de la imagen utilizando la diferencia escalada

Esto (todavía) funciona para mi situación. No sé si ambos usamos (d) los mismos sistemas de coordenadas, pero algo como esto le ayudará a escalar adecuadamente la imagen en el centro del gesto multitáctil.

Me tomó realmente mucho tiempo para conseguir este trabajo .. sin embargo gracias por casi código de trabajo! No estoy seguro de que estaba simplemente jugando o lo que pero con estos cambios en el código Tengo mi trabajo de zoom como yo quería! Espero que esto sea seguro tiempo someones.

 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; 

Al principio scaleAtm = 1.

  • Ubuntu PPA para Android SDK / NDK?
  • Mover las carpetas android-sdk y sdk a otra unidad
  • Android studio sdk versión 22 excepción durante la renderización: action_bar
  • ADT Plugin desapareció en Eclipse
  • SDK de Android facebook como JAR
  • ¿Cómo puedo emular la red 4G (LTE) en Android SDK
  • Android studio 2.3 canary falta 'Launch Standalone SDK Manager' opción en 'SDK Manager'
  • No se puede iniciar la actividad ComponentInfo {...}: java.lang.NullPointerException
  • Superpowered SDK: Implementación de SuperpoweredRecorder.h y configuración de rutas de grabación
  • La aplicación de Android se bloquea después de la versión de actualización de las herramientas de SDK (NoClassDefFound, versión de la herramienta 22)
  • No se pueden publicar anuncios de AdMob en android con google SDK
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.