2010-11-19 15 views
28

Attualmente sto sviluppando per Android (la mia prima app) un'applicazione che consente agli utenti di vedere la mappa della metropolitana e di essere in grado di pizzicare lo zoom e trascinare.android imageView: impostazione dei parametri di ingrandimento e trascinamento zoom

Attualmente sto modificando il codice trovato in Hello Android, 3rd Edition e ho ottenuto il pizzicamento dello zoom e il trascinamento per lavorare. Sto usando Matrix come scala del mio layout.

Tuttavia mi hanno ora 3 problemi:

  1. Ho provato molte cose per limitare i parametri di resistenza, ma io non riesco a fermarlo trascinato fuori dalla vista padre (e in realtà può non essere più visibili) . Ho provato a impostare i parametri di layout nel file XML e semplicemente non funziona.

  2. Posso pizzicare lo zoom bene ma ho problemi, ancora una volta, limitando la quantità di zoom. Sto cercando di giocare con l'impostazione di max_zoom e min_zoom per limitare il valore di ridimensionamento (posterò il mio codice dopo)

  3. Ho anche problemi a cercare di mappare una coordinata sulla mia immagine in modo che le persone possano fare clic su certi parti (il punto di questo è di consentire agli utenti di fare clic su una stazione sulla mappa e visualizzare le informazioni su di esso)

ho la sensazione che sto avendo difficoltà perché sto utilizzando la scala della matrice.

Ecco il mio codice corrente:

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 (niente piuttosto semplice, in realtà complicata):

<?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 aggiunto il tema in modo che non ci sia barra del titolo ed è a schermo intero)

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

risposta

5

Utilizzare il codice nel commento di Phyxdevel nel link qui sotto ZDNET Pinch Zoom Example.

Ha il codice per limitare il livello di panoramica e zoom.

18

Ho appena creato questa:

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

potrebbe essere utile per qualcuno ...

+0

Mi piace, tuttavia non riesco a riempire arbitrariamente ... – explodes

+0

Non avrebbe senso riempire per larghezza e altezza in quanto ciò (nella maggior parte dei casi) distorcerebbe l'immagine. Il framework utilizza l'attributo fill_parent per UNO degli assi e calcola l'altro in base al rapporto di aspetto dell'immagine. Sceglie gli assi in base all'orientamento del dispositivo. Paesaggio significa che la larghezza è fill_parent e l'altezza è calcolata, viceversa per il ritratto. –

+0

@Jason, sarebbe la dimensione del contenitore dell'immagine e l'immagine stessa sarebbe dimensionata indipendentemente all'interno dei limiti del contenitore. – explodes

7

So che questo è vecchio ma stavo cercando in questo modo e hanno una soluzione che funziona abbastanza bene.Subito dopo la sua dichiarazione switch e prima di impostare la matrice, è possibile limitare lo zoom in questo modo:

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

sto ancora lavorando come limitare la traduzione, ma questo dovrebbe funzionare per lo zoom limitante.

EDIT: Ecco una soluzione per limitare la traduzione. Come nota, lo sto facendo per una visualizzazione dell'immagine a schermo intero ed è per questo che utilizzo la larghezza e l'altezza del display nei miei fattori limitanti, ma è possibile utilizzare la larghezza e l'altezza della 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 volta, questo sarebbe andato subito dopo l'istruzione switch e proprio prima di impostare la matrice per l'immagine nella vista. Ho eliminato lo zoom limitando ad una funzione e si riflette sopra.

+0

Limitato il trascinamento verso l'alto e verso sinistra..Ma verso destra e verso il basso l'immagine va ancora. Qualche idea da risolvere? – playmaker420

+1

@ playmaker420 si prega di controllare la mia risposta qui sotto per limitare a destra e in basso. – Ankit

+0

@ Ankit .. L'ho risolto. Tutti i modi grazie per aver condiviso il codice – playmaker420

11

Un'altra opzione che potrebbe funzionare per alcuni è utilizzare uno WebView, che ha incorporato controlli di zoom.

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); 
+0

Posso dire, senza dubbio, questo è il modo migliore che ho trovato per gestire lo zoom di una bitmap. Spero che non ti dispiaccia che mando un link a un'altra domanda SO che potrebbe essere utile ad altri, ma questa risposta in combinazione con http://stackoverflow.com/questions/10849200/android-how-to-display-a-bitmap- in-a-webview ha fatto il trucco per caricare una bitmap creata dinamicamente in una WebView per lo zoom. Grazie ancora, ottima risposta! – zgc7009

0

è possibile utilizzare il codice seguente per limitare sotto ea destra

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

Ecco il codice completo per pinch zoom e pan (Touch.java con alcune modifiche che possono essere utilizzati praticamente)

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

} 
Problemi correlati