studio simpleongesturelistener recognition event android drag-and-drop imageview zoom pinch

simpleongesturelistener - android imageView: configuración de los parámetros de arrastre y pellizcar zoom



gestures android studio (7)

Acabo de crear esto:

https://github.com/jasonpolites/gesture-imageview

Puede ser útil para alguien ...

Actualmente estoy desarrollando para Android (mi primera aplicación) una aplicación que permite a los usuarios ver el mapa del metro y poder pellizcar y arrastrar.

Actualmente estoy modificando el código que se encuentra en Hello Android, 3ra Edición y obtuve el efecto pellizcar y arrastrar para trabajar. Estoy usando Matrix como mi escala de diseño.

Sin embargo ahora tengo 3 problemas:

  1. Intenté muchas cosas para limitar los parámetros de arrastre, pero parece que no puedo evitar que se arrastre desde la vista principal (y puede desaparecer de la vista). Intenté configurar los parámetros de diseño en el archivo XML y simplemente no funciona.

  2. Puedo pellizcar bien el zoom, pero tengo problemas, una vez más, lo que limita la cantidad de zoom. Estoy tratando de jugar con la configuración de un max_zoom y min_zoom para limitar el valor de escala (voy a publicar mi código después)

  3. También tengo problemas para tratar de asignar una coordenada en mi imagen para que las personas puedan hacer clic en ciertas partes (el objetivo de esto es permitir que los usuarios hagan clic en una estación en el mapa y visualicen información al respecto)

Tengo la sensación de que estoy teniendo problemas porque estoy usando la escala de la matriz.

Aquí está mi código actual:

Touch.java

package org.example.touch; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.PointF; import android.os.Bundle; import android.util.FloatMath; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.GridView; import android.widget.ImageView; public class Touch extends Activity implements OnTouchListener { private static final String TAG = "Touch"; private static final float MIN_ZOOM = 1.0f; private static final float MAX_ZOOM = 5.0f; // 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; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView view = (ImageView) findViewById(R.id.imageView); //view.setLayoutParams(new GridView.LayoutParams(85, 85)); view.setScaleType(ImageView.ScaleType.FIT_CENTER); view.setOnTouchListener(this); } public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; view.setScaleType(ImageView.ScaleType.MATRIX); float scale; // Dump touch event to log dumpEvent(event); // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: //first finger down only savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG" ); mode = DRAG; break; case MotionEvent.ACTION_UP: //first finger lifted case MotionEvent.ACTION_POINTER_UP: //second finger lifted mode = NONE; Log.d(TAG, "mode=NONE" ); break; case MotionEvent.ACTION_POINTER_DOWN: //second finger down oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 5f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM" ); } break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { //movement of first finger matrix.set(savedMatrix); if (view.getLeft() >= -392){ matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); } } else if (mode == ZOOM) { //pinch zooming float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 5f) { matrix.set(savedMatrix); scale = newDist / oldDist; **//thinking i need to play around with this value to limit it** matrix.postScale(scale, scale, mid.x, mid.y); } } break; } // Perform the transformation view.setImageMatrix(matrix); return true; // indicate event was handled } 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); } 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); } /** Show an event in the LogCat view, for debugging */ 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()); } }

main.xml (algo realmente simple nada complicado):

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/imageView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/map" android:scaleType="matrix" > </ImageView> </FrameLayout>

AndroidManifest.xml (solo se agregó el tema para que no haya una barra de título y se muestre en pantalla completa)

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.touch" android:versionCode="7" android:versionName="1.0" > <application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > <activity android:name=".Touch" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="7" /> </manifest>


Aquí está el código completo para pellizcar y panoramizar (Touch.java con algunas modificaciones que se pueden usar prácticamente)

public class Touch implements OnTouchListener { // These matrices will be used to move and zoom image public static Matrix matrix = new Matrix(); public static 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; private static final float MAX_ZOOM = (float) 3; private static final float MIN_ZOOM = 1; int mode = NONE; // Remember some things for zooming PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; int width,height; @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; Rect bounds = view.getDrawable().getBounds(); width = bounds.right - bounds.left; height = bounds.bottom - bounds.top; // Dump touch event to log 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()); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if (oldDist > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: 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); if (newDist > 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } //---------------------------------------------------- limitZoom(matrix); limitDrag( matrix); //---------------------------------------------------- view.setImageMatrix(matrix); return true; // indicate event was handled } /** Show an event in the LogCat view, for debugging */ 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("]"); } /** 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); } private void limitZoom(Matrix m) { float[] values = new float[9]; m.getValues(values); float scaleX = values[Matrix.MSCALE_X]; float scaleY = values[Matrix.MSCALE_Y]; if(scaleX > MAX_ZOOM) { scaleX = MAX_ZOOM; } else if(scaleX < MIN_ZOOM) { scaleX = MIN_ZOOM; } if(scaleY > MAX_ZOOM) { scaleY = MAX_ZOOM; } else if(scaleY < MIN_ZOOM) { scaleY = MIN_ZOOM; } values[Matrix.MSCALE_X] = scaleX; values[Matrix.MSCALE_Y] = scaleY; m.setValues(values); } private void limitDrag(Matrix m) { float[] values = new float[9]; m.getValues(values); float transX = values[Matrix.MTRANS_X]; float transY = values[Matrix.MTRANS_Y]; float scaleX = values[Matrix.MSCALE_X]; float scaleY = values[Matrix.MSCALE_Y]; //--- limit moving to left --- float minX = (-width + 0) * (scaleX-1); float minY = (-height + 0) * (scaleY-1); //--- limit moving to right --- float maxX=minX+width*(scaleX-1); float maxY=minY+height*(scaleY-1); if(transX>maxX){transX = maxX;} if(transX<minX){transX = minX;} if(transY>maxY){transY = maxY;} if(transY<minY){transY = minY;} values[Matrix.MTRANS_X] = transX; values[Matrix.MTRANS_Y] = transY; m.setValues(values); } }



Otra opción que podría funcionar para algunos es usar un WebView , que tiene controles de zoom incorporados.

WebView webView = new WebView(this); webView.setBackgroundColor(0xff000000); webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY); webView.getSettings().setBuiltInZoomControls(true); webView.getSettings().setSupportZoom(true); //webView.getSettings().setDisplayZoomControls(false); // API 11 webView.loadDataWithBaseURL(null, getHtml(), "text/html", "UTF-8", null); mainView.addView(webView, -1, -2);


Sé que esto es viejo, pero estaba buscando hacer esto y tener una solución que funciona bastante bien. Justo después de su declaración de cambio y antes de establecer la matriz, puede limitar el zoom de la siguiente manera:

private void limitZoom(Matrix m) { float[] values = new float[9]; m.getValues(values); float scaleX = values[Matrix.MSCALE_X]; float scaleY = values[Matrix.MSCALE_Y]; if(scaleX > MAX_ZOOM) { scaleX = MAX_ZOOM; } else if(scaleX < MIN_ZOOM) { scaleX = MIN_ZOOM; } if(scaleY > MAX_ZOOM) { scaleY = MAX_ZOOM; } else if(scaleY < MIN_ZOOM) { scaleY = MIN_ZOOM; } values[Matrix.MSCALE_X] = scaleX; values[Matrix.MSCALE_Y] = scaleY; m.setValues(values); }

Todavía estoy trabajando en cómo limitar la traducción, pero esto debería funcionar para la limitación del zoom.

EDITAR: Aquí hay una solución para limitar la traducción. Solo como nota, estoy haciendo esto para una vista de pantalla completa, por eso utilizo el ancho y la altura de la pantalla en mis factores limitantes, pero también podría usar el ancho y el alto de su vista.

private void limitDrag(Matrix m) { float[] values = new float[9]; m.getValues(values); float transX = values[Matrix.MTRANS_X]; float transY = values[Matrix.MTRANS_Y]; float scaleX = values[Matrix.MSCALE_X]; float scaleY = values[Matrix.MSCALE_Y]; ImageView iv = (ImageView)findViewById(R.id.photo_view); Rect bounds = iv.getDrawable().getBounds(); int viewWidth = getResources().getDisplayMetrics().widthPixels; int viewHeight = getResources().getDisplayMetrics().heightPixels; int width = bounds.right - bounds.left; int height = bounds.bottom - bounds.top; float minX = (-width + 20) * scaleX; float minY = (-height + 20) * scaleY; if(transX > (viewWidth - 20)) { transX = viewWidth - 20; } else if(transX < minX) { transX = minX; } if(transY > (viewHeight - 80)) { transY = viewHeight - 80; } else if(transY < minY) { transY = minY; } values[Matrix.MTRANS_X] = transX; values[Matrix.MTRANS_Y] = transY; m.setValues(values); }

Una vez más, esto iría justo después de su instrucción de cambio y justo antes de establecer la matriz para la imagen en la vista. Rompí la limitación del zoom en una función también y se refleja arriba.


Usa el código en el comentario de Phyxdevel en el siguiente enlace ZDNET Pinch Zoom Example .

Él tiene el código para restringir el pan y el nivel de zoom.


puede usar el siguiente código para limitar bottom y right

float maxX = minX+viewWidth; int offsetY = 80; float maxY = minY+viewHeight-offsetY; if(x>maxX){ mPosX = maxX; } if(x<minX){ mPosX = minX; } if(y>maxY){ mPosY = maxY; } if(y<minY){ mPosY = minY; }