Android Image View pizca zoom

Estoy usando una muestra de código de Making Sense of Multitouch para ampliar la vista de la imagen. En ScaleListener agregué ScaleGestureDetector.getFocusX() and getFocusY() para que el contenido se ScaleGestureDetector.getFocusX() and getFocusY() al punto focal del gesto. Está funcionando bien.

El problema es que, en el primer multitouch, la posición de dibujo de la imagen completa cambia al punto de contacto actual y se amplía desde allí. ¿Podrías ayudarme a resolver este problema?

Aquí está mi ejemplo de código para TouchImageView.

 public class TouchImageViewSample extends ImageView { private Paint borderPaint = null; private Paint backgroundPaint = null; private float mPosX = 0f; private float mPosY = 0f; private float mLastTouchX; private float mLastTouchY; private static final int INVALID_POINTER_ID = -1; private static final String LOG_TAG = "TouchImageView"; // The 'active pointer' is the one currently moving our object. private int mActivePointerId = INVALID_POINTER_ID; public TouchImageViewSample(Context context) { this(context, null, 0); } public TouchImageViewSample(Context context, AttributeSet attrs) { this(context, attrs, 0); } private ScaleGestureDetector mScaleDetector; private float mScaleFactor = 1.f; // Existing code ... public TouchImageViewSample(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // Create our ScaleGestureDetector mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); borderPaint = new Paint(); borderPaint.setARGB(255, 255, 128, 0); borderPaint.setStyle(Paint.Style.STROKE); borderPaint.setStrokeWidth(4); backgroundPaint = new Paint(); backgroundPaint.setARGB(32, 255, 255, 255); backgroundPaint.setStyle(Paint.Style.FILL); } @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; } /* * (non-Javadoc) * * @see android.view.View#draw(android.graphics.Canvas) */ @Override public void draw(Canvas canvas) { super.draw(canvas); canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, borderPaint); } @Override public void onDraw(Canvas canvas) { canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, backgroundPaint); if (this.getDrawable() != null) { canvas.save(); canvas.translate(mPosX, mPosY); Matrix matrix = new Matrix(); matrix.postScale(mScaleFactor, mScaleFactor, pivotPointX, pivotPointY); // canvas.setMatrix(matrix); canvas.drawBitmap( ((BitmapDrawable) this.getDrawable()).getBitmap(), matrix, null); // this.getDrawable().draw(canvas); canvas.restre(); } } /* * (non-Javadoc) * * @see * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable * ) */ @Override public void setImageDrawable(Drawable drawable) { // Constrain to given size but keep aspect ratio int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); mLastTouchX = mPosX = 0; mLastTouchY = mPosY = 0; int borderWidth = (int) borderPaint.getStrokeWidth(); mScaleFactor = Math.min(((float) getLayoutParams().width - borderWidth) / width, ((float) getLayoutParams().height - borderWidth) / height); pivotPointX = (((float) getLayoutParams().width - borderWidth) - (int) (width * mScaleFactor)) / 2; pivotPointY = (((float) getLayoutParams().height - borderWidth) - (int) (height * mScaleFactor)) / 2; super.setImageDrawable(drawable); } float pivotPointX = 0f; float pivotPointY = 0f; private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); pivotPointX = detector.getFocusX(); pivotPointY = detector.getFocusY(); Log.d(LOG_TAG, "mScaleFactor " + mScaleFactor); Log.d(LOG_TAG, "pivotPointY " + pivotPointY + ", pivotPointX= " + pivotPointX); mScaleFactor = Math.max(0.05f, mScaleFactor); invalidate(); return true; } } 

Y aquí cómo lo usé en mi actividad.

 ImageView imageView = (ImageView) findViewById(R.id.imgView); int hMargin = (int) (displayMetrics.widthPixels * .10); int vMargin = (int) (displayMetrics.heightPixels * .10); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(displayMetrics.widthPixels - (hMargin * 2), (int)(displayMetrics.heightPixels - btnCamera.getHeight()) - (vMargin * 2)); params.leftMargin = hMargin; params.topMargin = vMargin; imageView.setLayoutParams(params); imageView.setImageDrawable(drawable); 

 @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub ImageView view = (ImageView) v; dumpEvent(event); // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG"); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; Log.d(TAG, "mode=NONE"); break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { // ... matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); } else if (mode == ZOOM) { float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } view.setImageMatrix(matrix); return true; } private void dumpEvent(MotionEvent event) { String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" }; StringBuilder sb = new StringBuilder(); int action = event.getAction(); int actionCode = action & MotionEvent.ACTION_MASK; sb.append("event ACTION_").append(names[actionCode]); if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) { sb.append("(pid ").append( action >> MotionEvent.ACTION_POINTER_ID_SHIFT); sb.append(")"); } sb.append("["); for (int i = 0; i < event.getPointerCount(); i++) { sb.append("#").append(i); sb.append("(pid ").append(event.getPointerId(i)); sb.append(")=").append((int) event.getX(i)); sb.append(",").append((int) event.getY(i)); if (i + 1 < event.getPointerCount()) sb.append(";"); } sb.append("]"); Log.d(TAG, sb.toString()); } /** Determine the space between the first two fingers */ private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } /** Calculate the mid point of the first two fingers */ private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } 

y no te olvides de establecer la propiedad scaleType en la matriz de la etiqueta ImageView como:

   

y las variables utilizadas son:

 // These matrices will be used to move and zoom image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; // Remember some things for zooming PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; String savedItemClicked; 

Puedes usar esta clase: TouchImageView

Hice mi propia vista de imagen personalizada con pellizcar para ampliar. No hay límites / fronteras en el código de Chirag Raval , por lo que el usuario puede arrastrar la imagen fuera de la pantalla. Esto lo arreglará.

Aquí está la clase CustomImageView:

  public class CustomImageVIew extends ImageView implements OnTouchListener { private Matrix matrix = new Matrix(); private Matrix savedMatrix = new Matrix(); static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; private int mode = NONE; private PointF mStartPoint = new PointF(); private PointF mMiddlePoint = new PointF(); private Point mBitmapMiddlePoint = new Point(); private float oldDist = 1f; private float matrixValues[] = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}; private float scale; private float oldEventX = 0; private float oldEventY = 0; private float oldStartPointX = 0; private float oldStartPointY = 0; private int mViewWidth = -1; private int mViewHeight = -1; private int mBitmapWidth = -1; private int mBitmapHeight = -1; private boolean mDraggable = false; public CustomImageVIew(Context context) { this(context, null, 0); } public CustomImageVIew(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomImageVIew(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.setOnTouchListener(this); } @Override public void onSizeChanged (int w, int h, int oldw, int oldh){ super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHeight = h; } public void setBitmap(Bitmap bitmap){ if(bitmap != null){ setImageBitmap(bitmap); mBitmapWidth = bitmap.getWidth(); mBitmapHeight = bitmap.getHeight(); mBitmapMiddlePoint.x = (mViewWidth / 2) - (mBitmapWidth / 2); mBitmapMiddlePoint.y = (mViewHeight / 2) - (mBitmapHeight / 2); matrix.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y); this.setImageMatrix(matrix); } } @Override public boolean onTouch(View v, MotionEvent event){ switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); mStartPoint.set(event.getX(), event.getY()); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if(oldDist > 10f){ savedMatrix.set(matrix); midPoint(mMiddlePoint, event); mode = ZOOM; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; case MotionEvent.ACTION_MOVE: if(mode == DRAG){ drag(event); } else if(mode == ZOOM){ zoom(event); } break; } return true; } public void drag(MotionEvent event){ matrix.getValues(matrixValues); float left = matrixValues[2]; float top = matrixValues[5]; float bottom = (top + (matrixValues[0] * mBitmapHeight)) - mViewHeight; float right = (left + (matrixValues[0] * mBitmapWidth)) -mViewWidth; float eventX = event.getX(); float eventY = event.getY(); float spacingX = eventX - mStartPoint.x; float spacingY = eventY - mStartPoint.y; float newPositionLeft = (left < 0 ? spacingX : spacingX * -1) + left; float newPositionRight = (spacingX) + right; float newPositionTop = (top < 0 ? spacingY : spacingY * -1) + top; float newPositionBottom = (spacingY) + bottom; boolean x = true; boolean y = true; if(newPositionRight < 0.0f || newPositionLeft > 0.0f){ if(newPositionRight < 0.0f && newPositionLeft > 0.0f){ x = false; } else{ eventX = oldEventX; mStartPoint.x = oldStartPointX; } } if(newPositionBottom < 0.0f || newPositionTop > 0.0f){ if(newPositionBottom < 0.0f && newPositionTop > 0.0f){ y = false; } else{ eventY = oldEventY; mStartPoint.y = oldStartPointY; } } if(mDraggable){ matrix.set(savedMatrix); matrix.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0); this.setImageMatrix(matrix); if(x)oldEventX = eventX; if(y)oldEventY = eventY; if(x)oldStartPointX = mStartPoint.x; if(y)oldStartPointY = mStartPoint.y; } } public void zoom(MotionEvent event){ matrix.getValues(matrixValues); float newDist = spacing(event); float bitmapWidth = matrixValues[0] * mBitmapWidth; float bimtapHeight = matrixValues[0] * mBitmapHeight; boolean in = newDist > oldDist; if(!in && matrixValues[0] < 1){ return; } if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){ mDraggable = true; } else{ mDraggable = false; } float midX = (mViewWidth / 2); float midY = (mViewHeight / 2); matrix.set(savedMatrix); scale = newDist / oldDist; matrix.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY); this.setImageMatrix(matrix); } /** Determine the space between the first two fingers */ private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float)Math.sqrt(x * x + y * y); } /** Calculate the mid point of the first two fingers */ private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } } 

Así es como puedes usarlo en tu actividad:

 CustomImageVIew mImageView = (CustomImageVIew)findViewById(R.id.customImageVIew1); mImage.setBitmap(your bitmap); 

Y diseño:

  // important 

Agregue la siguiente línea en build.gradle:

 compile 'com.commit451:PhotoView:1.2.4' 

o

 compile 'com.github.chrisbanes:PhotoView:1.3.0' 

En el archivo de Java:

 PhotoViewAttacher photoAttacher; photoAttacher= new PhotoViewAttacher(Your_Image_View); photoAttacher.update();