简体   繁体   English

画布上的 Android 缩放缩放位图

[英]Android scale zoom zoomout bitmap on canvas

I need to add following features in my app我需要在我的应用程序中添加以下功能

I have to display Bitmap into Canvas我必须将位图显示到画布中

Then user can zoom in and zoom out bitmap into Canvas然后用户可以放大和缩小位图到 Canvas

How to make it possible?如何使它成为可能? I only need it in Canvas not in ImageView我只需要在画布中而不是在 ImageView 中

All answers are not much helpful to me.. so i think to update my Question所有答案对我都没有多大帮助..所以我想更新我的问题

Basically i need a simple 2 button and a canvas...基本上我需要一个简单的 2 个按钮和一个画布...

on first button click the image on canvas can rotate/zoom in and zoomout and on clicking second button it must display zoomed or zoomed out image that was created by user and after that the user must not able to zoom it or zoomout that canvas在第一个按钮单击画布上的图像可以旋转/放大和缩小,在单击第二个按钮时,它必须显示由用户创建的放大或缩小的图像,之后用户不得放大或缩小该画布

If you zoom in and zoom out bitmap in canvas use below code fore that如果您放大和缩小画布中的位图,请使用以下代码

Add your code in your activity在您的活动中添加您的代码

MyView myView = new MyView(this);
    setContentView(myView);

and below your view.在你的视野之下。

public class MyView extends View {
private Drawable image;
private ScaleGestureDetector scaleDetector;
private float scaleFactor = 1.f;

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

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

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

private void init(Context ctx) {
    image = getResources().getDrawable(R.drawable.ic_launcher);
    image.setBounds(0, 0, image.getIntrinsicWidth(),
            image.getIntrinsicHeight());
    scaleDetector = new ScaleGestureDetector(ctx, new ScaleListener());
}


@Override
protected void onDraw(Canvas canvas) {
    canvas.save();
    canvas.scale(scaleFactor, scaleFactor);
    image.draw(canvas);
    canvas.restore();

};

@Override
public boolean onTouchEvent(MotionEvent ev) {
    scaleDetector.onTouchEvent(ev);
    return true;
}

private class ScaleListener extends
        ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        scaleFactor *= detector.getScaleFactor();
        scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 10.0f));
        invalidate();
        return true;
    }
}
}

You can use this custom view class, it provide drag along with zoom effect.您可以使用这个自定义视图类,它提供拖动和缩放效果。 I am not the original author of this class ,I copied it from this tutorial .我不是这门课的原作者,我是从本教程中复制的。 You can go through tutorial pages if you like see step by step how to achieve this effect.如果您愿意,可以浏览教程页面,逐步了解如何实现此效果。

public class ZoomView extends View {

    //These two constants specify the minimum and maximum zoom
    private static float MIN_ZOOM = 1f;
    private static float MAX_ZOOM = 5f;

    private float scaleFactor = 1.f;
    private ScaleGestureDetector detector;

    //These constants specify the mode that we're in
    private static int NONE = 0;
    private static int DRAG = 1;
    private static int ZOOM = 2;

    private int mode;

    //These two variables keep track of the X and Y coordinate of the finger when it first
    //touches the screen
    private float startX = 0f;
    private float startY = 0f;

    //These two variables keep track of the amount we need to translate the canvas along the X
    //and the Y coordinate
    private float translateX = 0f;
    private float translateY = 0f;

    //These two variables keep track of the amount we translated the X and Y coordinates, the last time we
    //panned.
    private float previousTranslateX = 0f;
    private float previousTranslateY = 0f;   
   //This flag reflects whether the finger was actually dragged across the screen
   private boolean dragged = true; 
   private final int displayWidth;
   private final int displayHeight;
   private DisplayMetrics displayMetrics;


    public ZoomView(Context context) {
        super(context);
        detector = new ScaleGestureDetector(getContext(), new ScaleListener());
       displayMetrics = new DisplayMetrics();
      ((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
      displayHeight = displayMetrics.heightPixels;
      displayWidth = displayMetrics.widthPixels;

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                mode = DRAG;

                //We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
                //amount for each coordinates This works even when we are translating the first time because the initial
                //values for these two variables is zero.               
                startX = event.getX() - previousTranslateX;
                startY = event.getY() - previousTranslateY;
                break;

            case MotionEvent.ACTION_MOVE:               
                translateX = event.getX() - startX;
                translateY = event.getY() - startY;
 
                //We cannot use startX and startY directly because we have adjusted their values using the previous translation values. 
                //This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
                double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) + 
                                            Math.pow(event.getY() - (startY + previousTranslateY), 2)
                                           );
 
                if(distance > 0) {
                   dragged = true;
                }               

                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                mode = ZOOM;
                break;
   
            case MotionEvent.ACTION_UP:
                mode = NONE;
                dragged = false;

                //All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and 
                //previousTranslate           
                previousTranslateX = translateX;
                previousTranslateY = translateY;
                break;

            case MotionEvent.ACTION_POINTER_UP:
                mode = DRAG;

                //This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
                //and previousTranslateY when the second finger goes up
                previousTranslateX = translateX;
                previousTranslateY = translateY;
                break;       
        }

        detector.onTouchEvent(event);

        //We redraw the canvas only in the following cases:
        //
        // o The mode is ZOOM 
        //        OR
        // o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
        //   set to true (meaning the finger has actually moved)
        if ((mode == DRAG && scaleFactor != 1f && dragged) || mode == ZOOM) {
            invalidate();
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();

        //We're going to scale the X and Y coordinates by the same amount
        canvas.scale(scaleFactor, scaleFactor);

        //If translateX times -1 is lesser than zero, let's set it to zero. This takes care of the left bound
        if((translateX * -1) < 0) {
           translateX = 0;
        }

        //This is where we take care of the right bound. We compare translateX times -1 to (scaleFactor - 1) * displayWidth.
        //If translateX is greater than that value, then we know that we've gone over the bound. So we set the value of 
        //translateX to (1 - scaleFactor) times the display width. Notice that the terms are interchanged; it's the same
        //as doing -1 * (scaleFactor - 1) * displayWidth
        else if((translateX * -1) > (scaleFactor - 1) * displayWidth) {
           translateX = (1 - scaleFactor) * displayWidth;
        }

        if(translateY * -1 < 0) {
           translateY = 0;
        }

        //We do the exact same thing for the bottom bound, except in this case we use the height of the display
        else if((translateY * -1) > (scaleFactor - 1) * displayHeight) {
           translateY = (1 - scaleFactor) * displayHeight;
        }

        //We need to divide by the scale factor here, otherwise we end up with excessive panning based on our zoom level
        //because the translation amount also gets scaled according to how much we've zoomed into the canvas.
        canvas.translate(translateX / scaleFactor, translateY / scaleFactor);

        /* The rest of your canvas-drawing code */
        canvas.restore();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();
            scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
            return true;
        }
    }
}

You can check the condition if (scaleFactor == 1.f) then set all variables to the default values and call postInvalidate() in method onTouchEvent .您可以检查条件if (scaleFactor == 1.f)然后将所有变量设置为默认值并在onTouchEvent方法中调用postInvalidate()

For example:例如:

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        scaleDetector.onTouchEvent(ev);
          if (scaleFactor <= 1.f){
              //set all variables of zooming and scrolling to default
              scaleFactor = 1.f;
              postinvalidate();
          }
        return true;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM