2011-10-19 49 views
6

Tôi đang tìm kiếm iphone như chạm và chụm phóng to bằng Android ImageView. Mike Ortiz đã thực hiện một số công việc tuyệt vời trên TouchImageView để phát hiện ranh giới. Mã của anh ta có thể được tìm thấy here.Nhấn đúp để thu phóng và chụm để thu phóng trên ImageView trong android

Mã này chỉ thiếu một điều, tức là nhấn đúp để thu phóng. Có ai có thể giúp thêm tính năng này vào mã Mike Ortiz không?

+0

Thực ra, TouchImageView của Mike Ortiz chứa zoom đúp. Xem bài đăng này: http://stackoverflow.com/questions/7491519/how-does-touchimageview-works/7493485#7493485 – Halil

+0

Bạn đúng @Halil. Tuy nhiên, sự hỗ trợ đó đã được thêm vào sau. – Mazhar

Trả lời

6

Pinch Zoom trên ImageView trong Android với xử lý Định hướng

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Matrix; 
import android.graphics.Paint; 
import android.graphics.PointF; 
import android.os.Handler; 
import android.util.AttributeSet; 
import android.util.FloatMath; 
import android.util.Log; 
import android.view.GestureDetector; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.GestureDetector.SimpleOnGestureListener; 

public class ZoomableImageView extends View { 
    private static final String TAG = "ZoomableImageView";  

    private Bitmap imgBitmap = null; 

    private int containerWidth; 
    private int containerHeight; 

    Paint background; 

    //Matrices will be used to move and zoom image 
    Matrix matrix = new Matrix(); 
    Matrix savedMatrix = new Matrix(); 

    PointF start = new PointF();  

    float currentScale; 
    float curX; 
    float curY; 

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

    //For animating stuff 
    float targetX; 
    float targetY; 
    float targetScale; 
    float targetScaleX; 
    float targetScaleY; 
    float scaleChange; 
    float targetRatio; 
    float transitionalRatio; 

    float easing = 0.2f; 
    boolean isAnimating = false; 

    float scaleDampingFactor = 0.5f; 

    //For pinch and zoom 
    float oldDist = 1f; 
    PointF mid = new PointF(); 

    private Handler mHandler = new Handler();  

    float minScale; 
    float maxScale = 8.0f; 

    float wpRadius = 25.0f; 
    float wpInnerRadius = 20.0f; 

    float screenDensity; 

    private GestureDetector gestureDetector; 

    public static final int DEFAULT_SCALE_FIT_INSIDE = 0; 
    public static final int DEFAULT_SCALE_ORIGINAL = 1; 

    private int defaultScale; 

    public int getDefaultScale() { 
     return defaultScale; 
    } 

    public void setDefaultScale(int defaultScale) { 
     this.defaultScale = defaultScale; 
    } 

    public ZoomableImageView(Context context) { 
     super(context);  
     setFocusable(true); 
     setFocusableInTouchMode(true); 

     screenDensity = context.getResources().getDisplayMetrics().density; 

     initPaints(); 
     gestureDetector = new GestureDetector(new MyGestureDetector());  
    } 

    public ZoomableImageView(Context context, AttributeSet attrs) { 
     super(context, attrs); 

     screenDensity = context.getResources().getDisplayMetrics().density;  
     initPaints(); 
     gestureDetector = new GestureDetector(new MyGestureDetector()); 

     defaultScale = ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE; 
    } 

    private void initPaints() { 
     background = new Paint(); 
    } 

    @Override 
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { 
     super.onSizeChanged(width, height, oldWidth, oldHeight); 

     //Reset the width and height. Will draw bitmap and change 
     containerWidth = width; 
     containerHeight = height; 

     if(imgBitmap != null) { 
      int imgHeight = imgBitmap.getHeight(); 
      int imgWidth = imgBitmap.getWidth(); 

      float scale; 
      int initX = 0; 
      int initY = 0;   

      if(defaultScale == ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE) {    
       if(imgWidth > containerWidth) {   
        scale = (float)containerWidth/imgWidth;   
        float newHeight = imgHeight * scale;   
        initY = (containerHeight - (int)newHeight)/2; 

        matrix.setScale(scale, scale); 
        matrix.postTranslate(0, initY); 
       } 
       else {   
        scale = (float)containerHeight/imgHeight; 
        float newWidth = imgWidth * scale; 
        initX = (containerWidth - (int)newWidth)/2; 

        matrix.setScale(scale, scale); 
        matrix.postTranslate(initX, 0); 
       } 

       curX = initX; 
       curY = initY; 

       currentScale = scale; 
       minScale = scale; 
      } 
      else { 
       if(imgWidth > containerWidth) {         
        initY = (containerHeight - (int)imgHeight)/2;     
        matrix.postTranslate(0, initY); 
       } 
       else {        
        initX = (containerWidth - (int)imgWidth)/2;     
        matrix.postTranslate(initX, 0); 
       } 

       curX = initX; 
       curY = initY; 

       currentScale = 1.0f; 
       minScale = 1.0f;    
      } 


      invalidate();   
     } 
    } 

    @Override 
    protected void onDraw(Canvas canvas) {    
     if(imgBitmap != null && canvas != null) 
     {           
      canvas.drawBitmap(imgBitmap, matrix, background);             
     } 
    } 

    //Checks and sets the target image x and y co-ordinates if out of bounds 
    private void checkImageConstraints() { 
     if(imgBitmap == null) { 
      return; 
     } 

     float[] mvals = new float[9]; 
     matrix.getValues(mvals); 

     currentScale = mvals[0]; 

     if(currentScale < minScale) {        
      float deltaScale = minScale/currentScale;     
      float px = containerWidth/2; 
      float py = containerHeight/2;   
      matrix.postScale(deltaScale, deltaScale, px, py); 
      invalidate(); 
     }  

     matrix.getValues(mvals); 
     currentScale = mvals[0]; 
     curX = mvals[2]; 
     curY = mvals[5]; 

     int rangeLimitX = containerWidth - (int)(imgBitmap.getWidth() * currentScale); 
     int rangeLimitY = containerHeight - (int)(imgBitmap.getHeight() * currentScale); 


     boolean toMoveX = false; 
     boolean toMoveY = false; 

     if(rangeLimitX < 0) { 
      if(curX > 0) { 
       targetX = 0; 
       toMoveX = true; 
      } 
      else if(curX < rangeLimitX) { 
       targetX = rangeLimitX; 
       toMoveX = true; 
      } 
     } 
     else { 
      targetX = rangeLimitX/2; 
      toMoveX = true; 
     } 

     if(rangeLimitY < 0) { 
      if(curY > 0) { 
       targetY = 0; 
       toMoveY = true; 
      } 
      else if(curY < rangeLimitY) { 
       targetY = rangeLimitY; 
       toMoveY = true; 
      } 
     } 
     else { 
      targetY = rangeLimitY/2; 
      toMoveY = true; 
     } 

     if(toMoveX == true || toMoveY == true) { 
      if(toMoveY == false) { 
       targetY = curY; 
      } 
      if(toMoveX == false) { 
       targetX = curX; 
      }   

      //Disable touch event actions 
      isAnimating = true; 
      //Initialize timer   
      mHandler.removeCallbacks(mUpdateImagePositionTask); 
      mHandler.postDelayed(mUpdateImagePositionTask, 100); 
     } 
    }  


    @Override 
    public boolean onTouchEvent(MotionEvent event) {  
     if(gestureDetector.onTouchEvent(event)) { 
      return true; 
     } 

     if(isAnimating == true) { 
      return true; 
     } 

     //Handle touch events here  
     float[] mvals = new float[9]; 
     switch(event.getAction() & MotionEvent.ACTION_MASK) { 
     case MotionEvent.ACTION_DOWN: 
      if(isAnimating == false) { 
       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; 

      matrix.getValues(mvals); 
      curX = mvals[2]; 
      curY = mvals[5]; 
      currentScale = mvals[0]; 

      if(isAnimating == false) {          
       checkImageConstraints(); 
      } 
     break; 

     case MotionEvent.ACTION_MOVE:   
      if(mode == DRAG && isAnimating == false) { 
       matrix.set(savedMatrix); 
       float diffX = event.getX() - start.x; 
       float diffY = event.getY() - start.y; 

       matrix.postTranslate(diffX, diffY); 

       matrix.getValues(mvals); 
       curX = mvals[2]; 
       curY = mvals[5]; 
       currentScale = mvals[0]; 
      } 
      else if(mode == ZOOM && isAnimating == false) { 
       float newDist = spacing(event);    
       if(newDist > 10f) { 
        matrix.set(savedMatrix); 
        float scale = newDist/oldDist;     
        matrix.getValues(mvals); 
        currentScale = mvals[0]; 

        if(currentScale * scale <= minScale) { 
         matrix.postScale(minScale/currentScale, minScale/currentScale, mid.x, mid.y); 
        }     
        else if(currentScale * scale >= maxScale) { 
         matrix.postScale(maxScale/currentScale, maxScale/currentScale, mid.x, mid.y); 
        } 
        else { 
         matrix.postScale(scale, scale, mid.x, mid.y); 
        } 


        matrix.getValues(mvals); 
        curX = mvals[2]; 
        curY = mvals[5]; 
        currentScale = mvals[0];          
       } 
      } 

     break;        
     } 

     //Calculate the transformations and then invalidate 
     invalidate(); 
     return true; 
    } 

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

    public void setImageBitmap(Bitmap b) {  
     if(b != null) { 
      imgBitmap = b;    

      containerWidth = getWidth(); 
      containerHeight = getHeight(); 

      int imgHeight = imgBitmap.getHeight(); 
      int imgWidth = imgBitmap.getWidth(); 

      float scale; 
      int initX = 0; 
      int initY = 0; 

      matrix.reset(); 

      if(defaultScale == ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE) {    
       if(imgWidth > containerWidth) {   
        scale = (float)containerWidth/imgWidth;   
        float newHeight = imgHeight * scale;   
        initY = (containerHeight - (int)newHeight)/2; 

        matrix.setScale(scale, scale); 
        matrix.postTranslate(0, initY); 
       } 
       else {   
        scale = (float)containerHeight/imgHeight; 
        float newWidth = imgWidth * scale; 
        initX = (containerWidth - (int)newWidth)/2; 

        matrix.setScale(scale, scale); 
        matrix.postTranslate(initX, 0); 
       } 

       curX = initX; 
       curY = initY; 

       currentScale = scale; 
       minScale = scale; 
      } 
      else { 
       if(imgWidth > containerWidth) { 
        initX = 0; 
        if(imgHeight > containerHeight) {      
         initY = 0; 
        } 
        else {      
         initY = (containerHeight - (int)imgHeight)/2; 
        } 

        matrix.postTranslate(0, initY); 
       } 
       else {        
        initX = (containerWidth - (int)imgWidth)/2; 
        if(imgHeight > containerHeight) { 
         initY = 0; 
        } 
        else { 
         initY = (containerHeight - (int)imgHeight)/2; 
        } 
        matrix.postTranslate(initX, 0); 
       } 

       curX = initX; 
       curY = initY; 

       currentScale = 1.0f; 
       minScale = 1.0f;    
      } 

      invalidate();   
     } 
     else { 
      Log.d(TAG, "bitmap is null"); 
     } 
    } 

    public Bitmap getPhotoBitmap() {  
     return imgBitmap; 
    } 


    private Runnable mUpdateImagePositionTask = new Runnable() { 
     public void run() {  
      float[] mvals; 

      if(Math.abs(targetX - curX) < 5 && Math.abs(targetY - curY) < 5) { 
       isAnimating = false; 
       mHandler.removeCallbacks(mUpdateImagePositionTask); 

       mvals = new float[9]; 
       matrix.getValues(mvals); 

       currentScale = mvals[0]; 
       curX = mvals[2]; 
       curY = mvals[5]; 

       //Set the image parameters and invalidate display 
       float diffX = (targetX - curX); 
       float diffY = (targetY - curY); 

       matrix.postTranslate(diffX, diffY); 
      } 
      else { 
       isAnimating = true; 
       mvals = new float[9]; 
       matrix.getValues(mvals); 

       currentScale = mvals[0]; 
       curX = mvals[2]; 
       curY = mvals[5]; 

       //Set the image parameters and invalidate display 
       float diffX = (targetX - curX) * 0.3f; 
       float diffY = (targetY - curY) * 0.3f; 

       matrix.postTranslate(diffX, diffY);    
       mHandler.postDelayed(this, 25);    
      } 

      invalidate();   
     } 
    }; 

    private Runnable mUpdateImageScale = new Runnable() { 
     public void run() {   
      float transitionalRatio = targetScale/currentScale;   
      float dx; 
      if(Math.abs(transitionalRatio - 1) > 0.05) { 
       isAnimating = true;    
       if(targetScale > currentScale) {          
        dx = transitionalRatio - 1; 
        scaleChange = 1 + dx * 0.2f; 

        currentScale *= scaleChange; 

        if(currentScale > targetScale) { 
         currentScale = currentScale/scaleChange; 
         scaleChange = 1; 
        } 
       } 
       else {         
        dx = 1 - transitionalRatio;     
        scaleChange = 1 - dx * 0.5f; 
        currentScale *= scaleChange; 

        if(currentScale < targetScale) { 
         currentScale = currentScale/scaleChange; 
         scaleChange = 1; 
        } 
       } 


       if(scaleChange != 1) { 
        matrix.postScale(scaleChange, scaleChange, targetScaleX, targetScaleY);    
        mHandler.postDelayed(mUpdateImageScale, 15); 
        invalidate(); 
       } 
       else { 
        isAnimating = false; 
        scaleChange = 1;     
        matrix.postScale(targetScale/currentScale, targetScale/currentScale, targetScaleX, targetScaleY); 
        currentScale = targetScale; 
        mHandler.removeCallbacks(mUpdateImageScale); 
        invalidate(); 
        checkImageConstraints(); 
       }    
      } 
      else { 
       isAnimating = false; 
       scaleChange = 1;    
       matrix.postScale(targetScale/currentScale, targetScale/currentScale, targetScaleX, targetScaleY); 
       currentScale = targetScale; 
       mHandler.removeCallbacks(mUpdateImageScale); 
       invalidate(); 
       checkImageConstraints(); 
      }        
     } 
    }; 

    /** 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("]"); 
    } 

    class MyGestureDetector extends SimpleOnGestureListener { 
     @Override 
     public boolean onDoubleTap(MotionEvent event) {   
      if(isAnimating == true) { 
       return true; 
      } 

      scaleChange = 1; 
      isAnimating = true; 
      targetScaleX = event.getX(); 
      targetScaleY = event.getY(); 

      if(Math.abs(currentScale - maxScale) > 0.1) {   
       targetScale = maxScale; 
      } 
      else { 
       targetScale = minScale; 
      } 
      targetRatio = targetScale/currentScale; 
      mHandler.removeCallbacks(mUpdateImageScale); 
      mHandler.post(mUpdateImageScale);   
      return true; 
     } 

     @Override 
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
      return super.onFling(e1, e2, velocityX, velocityY); 
     } 

     @Override 
     public boolean onDown(MotionEvent e) { 
      return false; 
     } 
    } 
} 
+0

Cách sử dụng mã này – ashutiwari4

+0

Nơi bạn đang thêm ImageView thay thế bằng ZoomableImageView. Bạn có thể google cách thêm chế độ xem tùy chỉnh vào bố cục. –

+0

Tôi đang sử dụng xml để xem hình ảnh, khi tôi viết tên lớp trong xml tôi nhận được lỗi lạm phát. khi tôi sử dụng nó thông qua java nó chỉ cho tôi thấy một màn hình trống. – ashutiwari4

0

ImageView Zoomable với người nghe SingleTap

import android.content.Context; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 

import it.sephiroth.android.library.imagezoom.ImageViewTouch; 

public class MyZoomableImageViewTouch extends ImageViewTouch 
{ 

    static final float SCROLL_DELTA_THRESHOLD = 1.0f; 

    public MyZoomableImageViewTouch(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
     init(); 
    } 

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

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

    private void init() { 
     View.OnTouchListener listener = new View.OnTouchListener() { 
      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       if (getScale() > 1f) { 
       getParent().requestDisallowInterceptTouchEvent(true); 
       } else { 
       getParent().requestDisallowInterceptTouchEvent(false); 
       } 
       return false; 
      } 
      }; 
      setOnTouchListener(listener); 
      setDisplayType(DisplayType.FIT_TO_SCREEN); 
    } 

    @Override 
    protected float onDoubleTapPost(float scale, float maxZoom) { 
     if (scale != 1f) { 
      mDoubleTapDirection = 1; 
      return 1f; 
     } 
     if (mDoubleTapDirection == 1) { 
      mDoubleTapDirection = -1; 
      if ((scale + (mScaleFactor * 2)) <= maxZoom) { 
       return scale + mScaleFactor; 
      } else { 
       mDoubleTapDirection = -1; 
       return maxZoom; 
      } 
     } else { 
      mDoubleTapDirection = 1; 
      return 1f; 
     } 
    } 

    @Override 
    public boolean canScroll(int direction) { 
     RectF bitmapRect = getBitmapRect(); 
     updateRect(bitmapRect, mScrollRect); 
     Rect imageViewRect = new Rect(); 
     getGlobalVisibleRect(imageViewRect); 

     if (null == bitmapRect) { 
      return false; 
     } 

     if (Math.abs(bitmapRect.right - imageViewRect.right) < SCROLL_DELTA_THRESHOLD) { 
      if (direction < 0) { 
       return false; 
      } 
     } 

     if (Math.abs(bitmapRect.left - mScrollRect.left) < SCROLL_DELTA_THRESHOLD) { 
      if (direction > 0) { 
       return false; 
      } 
     } 
     return true; 
    } 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) 
    { 
     if (getScale() == 1f) return false; 
     if (distanceX != 0 && !canScroll((int) -distanceX)) { 
      getParent().requestDisallowInterceptTouchEvent(false); 
      return false; 
     } else { 
      getParent().requestDisallowInterceptTouchEvent(true); 
      mUserScaled = true; 
      scrollBy(-distanceX, -distanceY); 
      invalidate(); 
      return true; 
     } 
    } 
} 

Sử dụng phương pháp này cho tap đơn

imageView.setSingleTapListener(new ImageViewTouch.OnImageViewTouchSingleTapListener() 
    { 
     @Override 
     public void onSingleTapConfirmed() 
     { 
     } 
    } 
Các vấn đề liên quan