2010-12-10 6 views

Antwort

2

Der folgende Code funktioniert großartig! Sie müssen nur kopieren und einfügen:

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

Wie diesen Code verwenden? – ashutiwari4

+0

Erstellen Sie einfach eine Klasse namens ZoomableImageView, kopieren und fügen Sie den gesamten Code ein. Fügen Sie diese Ansicht dann entweder in Ihre Layoutdatei oder programmgesteuert ein und verwenden Sie die Methode setImageBitmap zum Zuweisen eines Bildes, das zoombar sein soll. Zoom wird direkt in der ZoomableImageView-Klasse (onTouch-Methode) behandelt. – kinghomer