画布上的Android缩放缩放缩小位图

问题描述 投票:5回答:3

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

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

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

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

所有答案对我都没有太大帮助。所以我想更新我的问题

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

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

android canvas bitmap zoom
3个回答
7
投票

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

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

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;    

        public ZoomView(Context context) {
            super(context);
            detector = new ScaleGestureDetector(getContext(), new ScaleListener());
        }

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

0
投票

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

例如:

    @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;
    }
© www.soinside.com 2019 - 2024. All rights reserved.