Vista de imagen de Android

Estoy usando código de ejemplo de Hacer sentido de Multitouch para ampliar la vista de imagen. En ScaleListener he añadido ScaleGestureDetector.getFocusX() and getFocusY() para que el contenido ScaleGestureDetector.getFocusX() and getFocusY() zoom sobre el punto focal del gesto. Está funcionando bien.

El problema es que, en el primer multitouch, la posición de dibujo de toda la imagen está cambiando al punto de contacto actual y ampliando desde allí. ¿Podría 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.restore(); } } /* * (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é dentro de 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 se olvide de establecer la propiedad scaleType a la matriz de ImageView etiqueta como:

 <ImageView android:id="@+id/imageEnhance" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="15dp" android:background="@drawable/enhanceimageframe" android:scaleType="matrix" > </ImageView> 

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; 

Puede utilizar esta clase: TouchImageView

Hice mi propia imagen personalizada con pellizco para hacer zoom. No hay límites / bordes 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 puede utilizarlo en su actividad:

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

Y diseño:

 <your.package.name.CustomImageVIew android:id="@+id/customImageVIew1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="15dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:scaleType="matrix"/> // important 

Añada la línea de abajo en build.gradle:

 compile 'com.commit451:PhotoView:1.2.4' 

o

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

En el archivo Java:

 PhotoViewAttacher photoAttacher; photoAttacher= new PhotoViewAttacher(Your_Image_View); photoAttacher.update(); 
  • Cómo detectar MotionEvent.ACTION_DOWN en el servicio Android
  • Searchbar cambio de posición del pulgar cuando el usuario pulsa las teclas de volumen del dispositivo
  • ¿Cómo usar MediaController.MediaPlayerControl?
  • ¿Cómo puedo actualizar correctamente AppWidget?
  • ¿Cuándo es necesario usar singleTop launchMode en un widget o aplicación de Android?
  • ¿Cómo iniciar un cuadro de diálogo desde un widget?
  • ¿Cómo actualizar vista de un widget en el botón de clic en android?
  • Cómo capturar los cambios de tamaño de widget en dispositivos donde onAppWidgetOptionsChanged no se llama?
  • ¿Cómo usar un textView para la cuenta atrás a cero?
  • RemoteViewsFactory llamado getViewAt cuando el dataset vacío
  • Android.widget, textView no se puede convertir en android.widget, botón
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.