2011-09-20 51 views
5

我有良好的工作TouchImageView,我想知道它是如何工作的代碼: 我只是想捏是縮放,或使用雙擊放大任何imageview我選擇,當我放大我回到圖像的原始大小。 TouchImageView.java:TouchImageView如何工作?

public class TouchImageView extends ImageView { 

Matrix matrix = new Matrix(); 

static final int NONE = 0; 
static final int DRAG = 1; 
static final int ZOOM = 2; 
int mode = NONE; 

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; 

Context context; 


public TouchImageView(Context context) { 
super(context); 
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) { 
     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 ScaleGestureDetector.SimpleOnScaleGestureListener { 
@Override 
public boolean onScaleBegin(ScaleGestureDetector detector) { 
    mode = ZOOM; 
    return true; 
} 

@Override 
public boolean onScale(ScaleGestureDetector detector) { 
    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); 
} 

} 

要使用是我創建了一個私有類:

private class CreateImage extends AsyncTask<String, Void, Drawable> { 
    protected void onPreExecute() { 
    } 

    protected Drawable doInBackground(String... urls) { 
     InputStream is; 
     Drawable d = null ; 
     try { 
      is = (InputStream)new URL(urls[0]).getContent(); 
      d = Drawable.createFromStream(is, "Image"); 
      return d; 
     } catch (MalformedURLException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return d; 
    } 
    protected void onPostExecute(Drawable d) { 
     touch.setMaxZoom(4f); 
     touch.setImageDrawable(d); 
     setContentView(touch); 
    } 
} 
public void createUrlImage(String url){ 
    new CreateImage().execute(url); 
} 

,並在OnCreate()我把createUrlImage(URL)。 我修改TouchImageView加入:

public void setImageDrawable(Drawable dr) { 
super.setImageDrawable(dr); 
bmWidth = dr.getIntrinsicWidth(); 
bmHeight = dr.getIntrinsicHeight(); 
} 

回答

6

編輯:槍王變焦,弗林和其他功能已經被添加到TouchImageView因爲我本來回答了這個問題。你可以在github here上查看它。


我加了一些使用細節原來的職位here。代碼已經具有縮放和平移以及邊界。此外,縮小將返回到原始大小的圖像。

添加雙擊縮放將需要更多工作。您必須使用GestureDetector並覆蓋onDoubleTap和onSingleTapConfirmed。然後,您需要確保將觸摸事件傳遞給gestureDetector,而不會干擾其餘代碼(請參閱onTouch開始時如何將事件傳遞給mScaleDetector)。你會希望擺脫ACTION_UP中的performClick()調用,而將其放置在onSingleTapConfirmed中。您可以檢查this answer獲取一些骨架代碼,以便開始實施GestureDetector。

讓我知道,如果你設法讓雙擊縮放固體,我會將你的變化添加到原來的帖子和Github回購。

+0

但我不能把TouchImageView放在Xml佈局中呢? – Tsunaze

+0

而我想要傳遞的圖像是我從Asynctask獲得的可繪圖。 – Tsunaze

+0

我修改了一下,放了一個drawable而不是位圖,它正在工作,但我無法通過Asynctask傳遞drawable。 – Tsunaze