2011-10-09 52 views
5

Tôi đang sửa đổi TouchImageView (https://github.com/MikeOrtiz/TouchImageView/issues) để phóng to và thu nhỏ khi bạn nhấn đúp. Tôi đã bắt đầu theo bài đăng này - How does TouchImageView works? và đã thêm phát hiện cử chỉ.Làm cách nào để sửa đổi TouchImageView bằng cách nhấn đúp để phóng to và thu nhỏ?

Bây giờ tôi phải triển khai phóng to và thu nhỏ mà tôi không chắc chắn cách thực hiện. Đây là mã tôi có cho đến nay với các phương pháp zoomIn và zoomOut chưa được thực hiện. Bất cứ ai biết làm thế nào để làm điều này? Ngoài ra, tôi nhận thấy rằng việc thu nhỏ chụm không thực sự phóng to đến vị trí mà bạn chụm, vì vậy tôi hy vọng rằng điều này có thể được thực hiện để hoạt động giống như phóng to thu nhỏ của gallery3D. Cảm ơn.

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

kiểm tra [ngã ba này] (https://github.com/Dreddik/AndroidTouchGallery) của ** TouchImageView ** với việc thực hiện chạm để thu phóng – Sash0k

Trả lời

8

câu trả lời của tôi có thể không chính xác cụ thể cho vấn đề của bạn, nhưng nó bao gồm ImageView Zooom trong/ra, nhấn đúp, Bounding image trong Imageview khi được phóng to, Tóm lại chính xác như ứng dụng Thư viện mặc định của Android

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

Khi blog nói:

Miễn là Android không có tiện ích ImageView tích hợp với khả năng thu phóng và cuộn Tôi cố gắng tự tạo một tiện ích mở rộng từ kho lưu trữ google.

Kết quả khá đẹp nên tôi đăng ở đây mã nguồn, nếu bất kỳ ai quan tâm hoặc đơn giản là không muốn lãng phí thời gian tạo tài khoản mới.

+0

Hoạt động tốt - cảm ơn. – timothyjc

3

Tăng gấp đôi zoom hiện tại để phóng to, sau đó quay trở lại mức zoom gốc:

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

Bạn có thể muốn dịch các ma trận để tập trung vào các điểm người dùng nhấp đúp.

+0

Điều này dường như không hoạt động đối với tôi trên SGS2 của tôi .. phóng to vào một điểm và sau đó không thu nhỏ. – timothyjc

+0

Ah xin lỗi, không đọc tất cả mã của bạn. Đặt boolean khi phóng to/thu nhỏ và sử dụng nó trong hàm onDoubleTap thay vì isZoomed – FunkTheMonk

0

Với lớp TouchImageView trên, nếu bạn muốn áp dụng Double Tap, bạn có thể làm một số bước sau: biến

  1. Declare:

    GestureDetector mDoubleTap; 
    
  2. Init trong hàm tạo:

    mDoubleTap = new GestureDetector(new DoubleTapGestureListener()); 
    
  3. ký trong onTouch():

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
        mDoubleTap.onTouchEvent(event); 
        ... 
    } 
    
  4. Viết phương pháp handleScale() - coppied từ onScale() phương pháp - như bên dưới:

    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. Đặt nó trong zoomIn() phương pháp là:

    public void zoomIn() { 
        handleScale(2.0f);// 2.0f is the scale ratio 
    } 
    
  6. Trong phương pháp ghi đè onScale(), bạn có thể sửa đổi như sau:

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

làm theo nguyên tắc DRY.

Lưu ý: nhấn đúp chỉ có hiệu lực với vùng chạm nhỏ.

Hãy cho tôi biết nếu nó phù hợp với bạn.

+0

nó đang hoạt động, nhưng khi tôi phóng to trung tâm của hình ảnh được dịch chuyển theo hướng touch.e.g. nếu bạn doubletapped trên bên phải của trung tâm vì vậy khi bạn phóng to hình ảnh được chuyển sang bên phải. Tôi đã thêm public void zoomOut() { handleScale (0.5f); isZoomed = false;}, bất kỳ ý tưởng nào? – sherlock

+0

Tôi có câu trả lời cho bạn, vui lòng kiểm tra bên dưới. Xin lỗi vì quá lâu để đăng ở đây –

1

@sherlock,

Nếu bạn muốn thu nhỏ khi nhấp đúp vào một lần nữa, bạn có thể viết một phương pháp như sau:

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

Lưu ý: Trong trường hợp một chiếc điện thoại có mềm Navigation Bar (như Nexus 5), bạn phải tính toán lại khoảng cách để dịch. Trong ví dụ của tôi, navBarHeight là biến được đặt bởi hàm:

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

Hãy cho tôi biết nếu nó có ích.

Các vấn đề liên quan