android imageView: setting drag and pinch zoom parameters

前端 未结 7 1760
太阳男子
太阳男子 2020-11-27 14:06

I am currently developing for Android (my first app) an application which lets users see the subway map and be able to pinch zoom and drag around.

I am currently mod

相关标签:
7条回答
  • 2020-11-27 14:23

    Use the code in the comment by Phyxdevel in the below link ZDNET Pinch Zoom Example.

    He has the code to restrict the pan and zoom level.

    0 讨论(0)
  • 2020-11-27 14:28

    I know this is old but I was looking into doing this and have a solution that works pretty well. Right after your switch statement and before you set the matrix, you can limit the zoom like so:

    private void limitZoom(Matrix m) {
    
        float[] values = new float[9];
        m.getValues(values);
        float scaleX = values[Matrix.MSCALE_X];
        float scaleY = values[Matrix.MSCALE_Y];
        if(scaleX > MAX_ZOOM) {
            scaleX = MAX_ZOOM;
        } else if(scaleX < MIN_ZOOM) {
            scaleX = MIN_ZOOM;
        }
    
        if(scaleY > MAX_ZOOM) {
            scaleY = MAX_ZOOM;
        } else if(scaleY < MIN_ZOOM) {
            scaleY = MIN_ZOOM;
        }
    
        values[Matrix.MSCALE_X] = scaleX;
        values[Matrix.MSCALE_Y] = scaleY; 
        m.setValues(values);
    }
    

    I'm still working out how to limit the translation but this should work for the zoom limiting.

    EDIT: Here's a solution for limiting the translation. Just as a note, I'm doing this for a full screen image view which is why I use the display width and height in my limiting factors but you could just as easily use the width and height of your view instead.

    private void limitDrag(Matrix m) {
        float[] values = new float[9];
        m.getValues(values);
        float transX = values[Matrix.MTRANS_X];
        float transY = values[Matrix.MTRANS_Y];
        float scaleX = values[Matrix.MSCALE_X];
        float scaleY = values[Matrix.MSCALE_Y];
    
        ImageView iv = (ImageView)findViewById(R.id.photo_view);
        Rect bounds = iv.getDrawable().getBounds();
        int viewWidth = getResources().getDisplayMetrics().widthPixels;
        int viewHeight = getResources().getDisplayMetrics().heightPixels;
    
        int width = bounds.right - bounds.left;
        int height = bounds.bottom - bounds.top;
    
        float minX = (-width + 20) * scaleX; 
        float minY = (-height + 20) * scaleY;
    
        if(transX > (viewWidth - 20)) {
            transX = viewWidth - 20;
        } else if(transX < minX) {
            transX = minX;
        }
    
        if(transY > (viewHeight - 80)) {
            transY = viewHeight - 80;
        } else if(transY < minY) {
            transY = minY;
        }
    
        values[Matrix.MTRANS_X] = transX;
        values[Matrix.MTRANS_Y] = transY; 
        m.setValues(values);
    }
    

    Once again, this would go right after your switch statement and right before you set the matrix for the image in the view. I broke out the zoom limiting into a function as well and it is reflected above.

    0 讨论(0)
  • 2020-11-27 14:34

    Download the source code. So you can also get this a) tap, b) drag, and c) pinch zoom. http://pragprog.com/titles/eband3/source_code

    0 讨论(0)
  • 2020-11-27 14:35

    Here is the complete code for pinch zoom and pan (Touch.java with some modifications that can be used practically)

    public class Touch implements OnTouchListener {  
    
     // These matrices will be used to move and zoom image  
    public static Matrix matrix = new Matrix();  
    public static Matrix savedMatrix = 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;
    private static final float MAX_ZOOM = (float) 3;
    private static final float MIN_ZOOM = 1;  
     int mode = NONE;  
    
     // Remember some things for zooming  
     PointF start = new PointF();  
     PointF mid = new PointF();  
     float oldDist = 1f;  
    
     int width,height;
    
     @Override  
     public boolean onTouch(View v, MotionEvent event) {
    
    
      ImageView view = (ImageView) v;
      Rect bounds = view.getDrawable().getBounds();
    
      width = bounds.right - bounds.left;
      height = bounds.bottom - bounds.top;
      // Dump touch event to log  
      dumpEvent(event);  
    
      // Handle touch events here...  
      switch (event.getAction() & MotionEvent.ACTION_MASK) {  
      case MotionEvent.ACTION_DOWN:  
       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;  
       break;  
      case MotionEvent.ACTION_MOVE:  
       if (mode == DRAG) {  
        // ...      
        matrix.set(savedMatrix);  
        matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);      
       } else if (mode == ZOOM) {  
        float newDist = spacing(event);  
        if (newDist > 10f) {  
         matrix.set(savedMatrix);  
         float scale = newDist / oldDist;  
         matrix.postScale(scale, scale, mid.x, mid.y);  
        }  
       }  
       break;  
      }  
    //----------------------------------------------------
      limitZoom(matrix);
      limitDrag( matrix);
    //----------------------------------------------------  
      view.setImageMatrix(matrix);  
      return true; // indicate event was handled  
     }  
    
     /** 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("]");  
     }  
    
     /** Determine the space between the first two fingers */  
     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);  
     }  
    
     /** Calculate the mid point of the first two fingers */  
     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);  
     }  
    
     private void limitZoom(Matrix m) {
    
            float[] values = new float[9];
            m.getValues(values);
            float scaleX = values[Matrix.MSCALE_X];
            float scaleY = values[Matrix.MSCALE_Y];
            if(scaleX > MAX_ZOOM) {
                scaleX = MAX_ZOOM;
            } else if(scaleX < MIN_ZOOM) {
                scaleX = MIN_ZOOM;
            }
    
            if(scaleY > MAX_ZOOM) {
                scaleY = MAX_ZOOM;
            } else if(scaleY < MIN_ZOOM) {
                scaleY = MIN_ZOOM;
            }
    
            values[Matrix.MSCALE_X] = scaleX;
            values[Matrix.MSCALE_Y] = scaleY; 
            m.setValues(values);
        }
    
    
     private void limitDrag(Matrix m) {
    
            float[] values = new float[9];
            m.getValues(values);
            float transX = values[Matrix.MTRANS_X];
            float transY = values[Matrix.MTRANS_Y];
            float scaleX = values[Matrix.MSCALE_X];
            float scaleY = values[Matrix.MSCALE_Y];
    //--- limit moving to left ---
            float minX = (-width + 0) * (scaleX-1); 
            float minY = (-height + 0) * (scaleY-1);
    //--- limit moving to right ---     
            float maxX=minX+width*(scaleX-1);
            float maxY=minY+height*(scaleY-1);
            if(transX>maxX){transX = maxX;}
            if(transX<minX){transX = minX;}
            if(transY>maxY){transY = maxY;}
            if(transY<minY){transY = minY;}
            values[Matrix.MTRANS_X] = transX;
            values[Matrix.MTRANS_Y] = transY; 
            m.setValues(values);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 14:42

    Another option that might work for some is to use a WebView, which has built in zoom controls.

    WebView webView = new WebView(this);
    webView.setBackgroundColor(0xff000000);
    webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
    webView.getSettings().setBuiltInZoomControls(true);
    webView.getSettings().setSupportZoom(true);
    //webView.getSettings().setDisplayZoomControls(false);  // API 11
    webView.loadDataWithBaseURL(null, getHtml(), "text/html", "UTF-8", null);
    mainView.addView(webView, -1, -2);
    
    0 讨论(0)
  • 2020-11-27 14:46

    you can use following code to limit bottom and right

    float maxX = minX+viewWidth; 
    int offsetY = 80;
            float maxY = minY+viewHeight-offsetY;
           if(x>maxX){
               mPosX = maxX;
           }
           if(x<minX){
               mPosX = minX;
           }
           if(y>maxY){
               mPosY = maxY;
           }
           if(y<minY){
               mPosY = minY;
           }
    
    0 讨论(0)
提交回复
热议问题