【问题标题】:Android scale zoom zoomout bitmap on canvas画布上的Android缩放缩放位图
【发布时间】:2014-09-10 04:54:38
【问题描述】:

我需要在我的应用中添加以下功能

我必须将位图显示到画布中

然后用户可以在画布中放大和缩小位图

如何使它成为可能? 我只需要在 Canvas 中而不是在 ImageView 中

所有答案对我没有多大帮助..所以我想更新我的问题

基本上我需要一个简单的 2 按钮和一个画布...

在第一个按钮上单击画布上的图像可以旋转/放大和缩小,在单击第二个按钮时,它必须显示由用户创建的放大或缩小的图像,之后用户不能对其进行缩放或缩小画布

【问题讨论】:

标签: android canvas bitmap zooming


【解决方案1】:

如果您在画布中放大和缩小位图,请使用下面的代码

在您的活动中添加您的代码

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

在你的视野之下。

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

【讨论】:

  • 如果我在画布上有多个位图,这是缩放它们,而不是单个
  • 我需要一个解决方案来缩放被捏合的位图,而不是整个画布。
【解决方案2】:

您可以使用这个自定义视图类,它提供拖动和缩放效果。 我不是这个类的原作者,我是从这个tutorial复制的。喜欢的可以去tutorial pages看看如何实现这个效果。

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

【讨论】:

    【解决方案3】:

    您可以检查条件if (scaleFactor == 1.f),然后将所有变量设置为默认值,并在方法onTouchEvent 中调用postInvalidate()

    例如:

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

    【讨论】:

      猜你喜欢
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-28
      • 2016-08-26
      • 2012-11-30
      相关资源
      最近更新 更多