2011-10-09 12 views
5

Sto modificando TouchImageView (https://github.com/MikeOrtiz/TouchImageView/issues) per ingrandire e rimpicciolire quando si tocca due volte. Ho iniziato come da questo post - How does TouchImageView works? e ho aggiunto il rilevamento dei gesti.Come posso modificare TouchImageView con un doppio tocco per ingrandire e rimpicciolire?

Ora devo implementare lo zoom in e lo zoom out che non sono sicuro di come fare. Ecco il codice che ho finora con i metodi zoomIn e zoomOut non implementati. Qualcuno sa come fare questo? Inoltre ho notato che lo zoom pizzico non fa realmente lo zoom nella posizione in cui pizzichi, quindi speravo che questo potesse essere fatto per comportarsi più come lo zoom pizzico di gallery3D. Grazie.

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Matrix; 
import android.graphics.PointF; 
import android.util.AttributeSet; 
import android.view.GestureDetector; 
import android.view.GestureDetector.SimpleOnGestureListener; 
import android.view.MotionEvent; 
import android.view.ScaleGestureDetector; 
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener; 
import android.view.View; 
import android.widget.ImageView; 

public class TouchImageView extends ImageView { 

private static final String TAG = TouchImageView.class.getSimpleName(); 

Matrix matrix = 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 last = new PointF(); 
PointF start = new PointF(); 
float minScale = 1f; 
float maxScale = 3f; 
float[] m; 

float redundantXSpace, redundantYSpace; 

float width, height; 
static final int CLICK = 3; 
float saveScale = 1f; 
float right, bottom, origWidth, origHeight, bmWidth, bmHeight; 

ScaleGestureDetector mScaleDetector; 

private GestureDetector gestureDetector; 

Context context; 

public TouchImageView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    init(context); 
} 

public TouchImageView(Context context) { 
    super(context); 
    init(context); 
} 

public void init(Context context) { 
    gestureDetector = new GestureDetector(new DoubleTapGestureListener()); 

    super.setClickable(true); 
    this.context = context; 
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 
    matrix.setTranslate(1f, 1f); 
    m = new float[9]; 
    setImageMatrix(matrix); 
    setScaleType(ScaleType.MATRIX); 

    setOnTouchListener(new OnTouchListener() { 

     @Override 
     public boolean onTouch(View v, MotionEvent event) { 

      if (gestureDetector.onTouchEvent(event)) { 
       return true; 
      } 

      mScaleDetector.onTouchEvent(event); 

      matrix.getValues(m); 
      float x = m[Matrix.MTRANS_X]; 
      float y = m[Matrix.MTRANS_Y]; 
      PointF curr = new PointF(event.getX(), event.getY()); 

      switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       last.set(event.getX(), event.getY()); 
       start.set(last); 
       mode = DRAG; 
       break; 
      case MotionEvent.ACTION_MOVE: 
       if (mode == DRAG) { 
        float deltaX = curr.x - last.x; 
        float deltaY = curr.y - last.y; 
        float scaleWidth = Math.round(origWidth * saveScale); 
        float scaleHeight = Math.round(origHeight * saveScale); 
        if (scaleWidth < width) { 
         deltaX = 0; 
         if (y + deltaY > 0) 
          deltaY = -y; 
         else if (y + deltaY < -bottom) 
          deltaY = -(y + bottom); 
        } else if (scaleHeight < height) { 
         deltaY = 0; 
         if (x + deltaX > 0) 
          deltaX = -x; 
         else if (x + deltaX < -right) 
          deltaX = -(x + right); 
        } else { 
         if (x + deltaX > 0) 
          deltaX = -x; 
         else if (x + deltaX < -right) 
          deltaX = -(x + right); 

         if (y + deltaY > 0) 
          deltaY = -y; 
         else if (y + deltaY < -bottom) 
          deltaY = -(y + bottom); 
        } 
        matrix.postTranslate(deltaX, deltaY); 
        last.set(curr.x, curr.y); 
       } 
       break; 

      case MotionEvent.ACTION_UP: 
       mode = NONE; 
       int xDiff = (int) Math.abs(curr.x - start.x); 
       int yDiff = (int) Math.abs(curr.y - start.y); 
       if (xDiff < CLICK && yDiff < CLICK) 
        performClick(); 
       break; 

      case MotionEvent.ACTION_POINTER_UP: 
       mode = NONE; 
       break; 
      } 
      setImageMatrix(matrix); 
      invalidate(); 
      return true; // indicate event was handled 
     } 

    }); 
} 

@Override 
public void setImageBitmap(Bitmap bm) { 
    super.setImageBitmap(bm); 
    bmWidth = bm.getWidth(); 
    bmHeight = bm.getHeight(); 
} 

public void setMaxZoom(float x) { 
    maxScale = x; 
} 

private class ScaleListener extends SimpleOnScaleGestureListener { 
    @Override 
    public boolean onScaleBegin(ScaleGestureDetector detector) { 
     mode = ZOOM; 
     return true; 
    } 

    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 

     LogUtil.i(TAG, detector.getScaleFactor() + " " + detector.getFocusX() + " " + detector.getFocusY()); 

     float mScaleFactor = (float) Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05); 
     float origScale = saveScale; 
     saveScale *= mScaleFactor; 
     if (saveScale > maxScale) { 
      saveScale = maxScale; 
      mScaleFactor = maxScale/origScale; 
     } else if (saveScale < minScale) { 
      saveScale = minScale; 
      mScaleFactor = minScale/origScale; 
     } 
     right = width * saveScale - width - (2 * redundantXSpace * saveScale); 
     bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 
     if (origWidth * saveScale <= width || origHeight * saveScale <= height) { 
      matrix.postScale(mScaleFactor, mScaleFactor, width/2, height/2); 
      if (mScaleFactor < 1) { 
       matrix.getValues(m); 
       float x = m[Matrix.MTRANS_X]; 
       float y = m[Matrix.MTRANS_Y]; 
       if (mScaleFactor < 1) { 
        if (Math.round(origWidth * saveScale) < width) { 
         if (y < -bottom) 
          matrix.postTranslate(0, -(y + bottom)); 
         else if (y > 0) 
          matrix.postTranslate(0, -y); 
        } else { 
         if (x < -right) 
          matrix.postTranslate(-(x + right), 0); 
         else if (x > 0) 
          matrix.postTranslate(-x, 0); 
        } 
       } 
      } 
     } else { 
      matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); 
      matrix.getValues(m); 
      float x = m[Matrix.MTRANS_X]; 
      float y = m[Matrix.MTRANS_Y]; 
      if (mScaleFactor < 1) { 
       if (x < -right) 
        matrix.postTranslate(-(x + right), 0); 
       else if (x > 0) 
        matrix.postTranslate(-x, 0); 
       if (y < -bottom) 
        matrix.postTranslate(0, -(y + bottom)); 
       else if (y > 0) 
        matrix.postTranslate(0, -y); 
      } 
     } 
     return true; 

    } 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    width = MeasureSpec.getSize(widthMeasureSpec); 
    height = MeasureSpec.getSize(heightMeasureSpec); 
    // Fit to screen. 
    float scale; 
    float scaleX = (float) width/(float) bmWidth; 
    float scaleY = (float) height/(float) bmHeight; 
    scale = Math.min(scaleX, scaleY); 
    matrix.setScale(scale, scale); 
    setImageMatrix(matrix); 
    saveScale = 1f; 

    // Center the image 
    redundantYSpace = (float) height - (scale * (float) bmHeight); 
    redundantXSpace = (float) width - (scale * (float) bmWidth); 
    redundantYSpace /= (float) 2; 
    redundantXSpace /= (float) 2; 

    matrix.postTranslate(redundantXSpace, redundantYSpace); 

    origWidth = width - 2 * redundantXSpace; 
    origHeight = height - 2 * redundantYSpace; 
    right = width * saveScale - width - (2 * redundantXSpace * saveScale); 
    bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 
    setImageMatrix(matrix); 
} 

class DoubleTapGestureListener extends SimpleOnGestureListener { 

    @Override 
    public boolean onDown(MotionEvent e) { 
     return true; 
    } 

    // event when double tap occurs 
    @Override 
    public boolean onDoubleTap(MotionEvent e) { 
     float x = e.getX(); 
     float y = e.getY(); 
     LogUtil.i(TAG, "Tapped at: (" + x + "," + y + ")"); 
     if (isZoomed()) { 
      zoomOut(); 
     } else { 
      zoomIn(); 
     } 
     return true; 
    } 

} 

public boolean isZoomed() { 
    return saveScale > minScale; // this seems to work 
} 

public void zoomIn() { 
    LogUtil.i(TAG, "Zooming in"); 
    // TODO: no idea how to do this 

} 

public void zoomOut() { 
    LogUtil.i(TAG, "Zooming out"); 
    // TODO: no idea how to do this 
} 

} 
+0

controllare [questa forcella] (https://github.com/Dreddik/AndroidTouchGallery) di ** TouchImageView ** con implementazione tap-to-zoom – Sash0k

risposta

8

La mia risposta potrebbe essere non proprio specifico per il problema, ma copre ImageView Zooom in/out, doppio tap, immagine delimitano in IMAGEVIEW quando il suo zoom, insomma è esattamente come l'applicazione Galleria di default di Android

http://blog.sephiroth.it/2011/04/04/imageview-zoom-and-scroll/

come il blog dice:

Finché Android non ha un built-in widget di ImageView con funzionalità di zoom e scorrimento che cerca di creare uno da solo partendo dal repository di Google.

Il risultato è abbastanza bello così sto postando qui il codice sorgente, se qualcuno è interessato, o semplicemente non vuole sprecare il tempo crearne uno nuovo.

+0

Funziona bene - grazie. – timothyjc

3

Raddoppia la corrente di zoom per ingrandire e poi torna al livello di zoom originale:

float oldScale = 1.0f; 
public void zoomIn() { 
    LogUtil.i(TAG, "Zooming in"); 
    oldScale = saveScale; 
    saveScale *= 2; 
    matrix.setScale(saveScale, saveScale); 
    setImageMatrix(matrix); 
    invalidate(); 
} 

public void zoomOut() { 
    LogUtil.i(TAG, "Zooming out"); 
    saveScale = oldScale; 
    matrix.setScale(saveScale, saveScale); 
    setImageMatrix(matrix); 
    invalidate(); 
} 

si potrebbe desiderare di tradurre la matrice per centrare sul punto l'utente fa doppio clic.

+0

Questo non sembra funzionare per me sul mio SGS2. ingrandisce in un punto e quindi non esegue lo zoom indietro. – timothyjc

+0

Ah scusa, non ho letto tutto il tuo codice. Imposta un valore booleano quando esegui lo zoom in/out e lo utilizzi nella funzione onDoubleTap invece di isZoomed – FunkTheMonk

0

Con sopra della classe TouchImageView, se si desidera applicare Double Tap, si possono fare alcune operazioni: variabile

  1. Declare:

    GestureDetector mDoubleTap; 
    
  2. Init in costruttore:

    mDoubleTap = new GestureDetector(new DoubleTapGestureListener()); 
    
  3. Registrati a onTouch():

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
        mDoubleTap.onTouchEvent(event); 
        ... 
    } 
    
  4. Scrivi il metodo handleScale() - coppied da onScale() metodo - come di seguito:

    private void handleScale(float mScaleFactor) { 
        float origScale = saveScale; 
        saveScale *= mScaleFactor; 
        if (saveScale > maxScale) { 
         saveScale = maxScale; 
         mScaleFactor = maxScale/origScale; 
        } else if (saveScale < minScale) { 
         saveScale = minScale; 
         mScaleFactor = minScale/origScale; 
        } 
        right = width * saveScale - width - (2 * redundantXSpace * saveScale); 
        bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 
        if (origWidth * saveScale <= width || origHeight * saveScale <= height) { 
         matrix.postScale(mScaleFactor, mScaleFactor, width/2, height/2); 
         if (mScaleFactor < 1) { 
          matrix.getValues(m); 
          float x = m[Matrix.MTRANS_X]; 
          float y = m[Matrix.MTRANS_Y]; 
          if (mScaleFactor < 1) { 
           if (Math.round(origWidth * saveScale) < width) { 
            if (y < -bottom) 
             matrix.postTranslate(0, -(y + bottom)); 
            else if (y > 0) 
             matrix.postTranslate(0, -y); 
           } else { 
            if (x < -right) 
             matrix.postTranslate(-(x + right), 0); 
            else if (x > 0) 
             matrix.postTranslate(-x, 0); 
           } 
          } 
         } 
        } else { 
         matrix.postScale(mScaleFactor, mScaleFactor, mScaleDetector.getFocusX(), mScaleDetector.getFocusY()); 
         matrix.getValues(m); 
         float x = m[Matrix.MTRANS_X]; 
         float y = m[Matrix.MTRANS_Y]; 
         if (mScaleFactor < 1) { 
          if (x < -right) 
           matrix.postTranslate(-(x + right), 0); 
          else if (x > 0) 
           matrix.postTranslate(-x, 0); 
          if (y < -bottom) 
           matrix.postTranslate(0, -(y + bottom)); 
          else if (y > 0) 
           matrix.postTranslate(0, -y); 
         } 
        } 
    } 
    
  5. Inserirlo in zoomIn() metodo come:

    public void zoomIn() { 
        handleScale(2.0f);// 2.0f is the scale ratio 
    } 
    
  6. Nel metodo di override onScale(), è possibile modificare come:

    @Override 
        public boolean onScale(ScaleGestureDetector detector) { 
         float mScaleFactor = detector.getScaleFactor(); 
         handleScale(mScaleFactor); 
         return true; 
        } 
    

a seguire principio DRY.

Nota: toccare due volte ha effetto solo con una piccola zona toccata.

Fammi sapere se funziona per voi.

+0

funziona, ma quando si esegue lo zoomout il centro dell'immagine viene spostato nella direzione del tocco.e.g. se si esegue il doppiaggio parziale al centro, così quando si esegue lo zoomout l'immagine viene spostata a destra. Ho aggiunto public void zoomOut() { handleScale (0.5f); isZoomed = false;}, qualche idea? – sherlock

+0

Ho una risposta per te, per favore controlla sotto. Mi dispiace perché è troppo lungo per postare qui –

1

@sherlock,

Se si vuole diminuire quando si fa doppio rubinetto di nuovo, è possibile scrivere un metodo come di seguito:

private void handleScaleWhenDoubleTap(float scaleFactor) { 
    //set original scale 
    float origScale = curScale; 
    //update current scale 
    curScale *= scaleFactor; 
    //fix current scale if it greater than max scale, recalculate scale factor 
    if (curScale > maxScale) { 
     curScale = maxScale; 
     scaleFactor = maxScale/origScale; 
    } 
    //fix current scale if it less than min scale, recalculate scale factor 
    else if (curScale < minScale) { 
     curScale = minScale; 
     scaleFactor = minScale/origScale; 
    } 
    //calculate right point, bottom point 
    right = (curScale - 1) * width - 2 * (redundantXSpace * curScale); 
    bottom = (curScale - 1) * height - 2 * (redundantYSpace * curScale); 
    //scale 
    matrix.postScale(scaleFactor, scaleFactor, width/2, height/2); 
    //translate 
    matrix.getValues(m); 
    float x = m[Matrix.MTRANS_X]; 
    float y = m[Matrix.MTRANS_Y]; 

    if (y + bottom < 0) { 
     if (x >= 0) { 
      matrix.postTranslate(-x + redundantXSpace, -(y + bottom + redundantYSpace)); 
     } else if (x + right < 0) { 
      matrix.postTranslate(-(x + right + redundantXSpace), -(y + bottom + redundantYSpace)); 
     } else { 
      matrix.postTranslate(0, -(y + bottom)); 
     } 
    } else if (y >= 0) { 
     if (x >= 0) { 
      matrix.postTranslate(-x + redundantXSpace, -y + redundantYSpace - navBarHeight); 
     } else if (x + right < 0) { 
      matrix.postTranslate(-(x + right + redundantXSpace), -y + redundantYSpace - navBarHeight); 
     } else { 
      matrix.postTranslate(0, -y); 
     } 
    } else { 
     if (x >= 0) { 
      matrix.postTranslate(-x, redundantYSpace - navBarHeight); 
     } else if (x + right < 0) { 
      matrix.postTranslate(-(x + right + redundantXSpace), redundantYSpace - navBarHeight); 
     } else { 
      matrix.postTranslate(0, -navBarHeight); 
     } 
    } 
} 

Nota: Nel caso in cui un telefono ha morbida barra di navigazione (come Nexus 5), è necessario ricalcolare la distanza da tradurre. Nel mio esempio, navBarHeight è la variabile che essere impostata dalla funzione:

public int getNavBarHeight(Context ctx) { 
     int id = ctx.getResources().getIdentifier("config_showNavigationBar", "bool", "android"); 
     boolean hasNavBar = id > 0 && ctx.getResources().getBoolean(id); 
     if (hasNavBar) { 
      int resourceId = ctx.getResources().getIdentifier("navigation_bar_height", "dimen", "android"); 
      if (resourceId > 0) { 
       return ctx.getResources().getDimensionPixelSize(resourceId); 
      } 
     } 
     return 0; 
    } 

farmi sapere se aiuta.

Problemi correlati