ZOOMVIEW帆布矩阵的Andr​​oid [英] ZoomView canvas matrix Android

查看:225
本文介绍了ZOOMVIEW帆布矩阵的Andr​​oid的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我采取从我对堆栈和其他网站上找到的例子可缩放视图。我也想绘图功能添加到视图。我能够得到的路径展现出来,但是比例是路要走从它后面的图像。予使用的示例机器人图像,其中我跟踪沿的形状和路径出现的左侧和上方。此外,变焦使其移动(图片下方)。

我一直在摆弄的OnDraw 方法,其中在画布上绘制,但收效甚微。我基本上是使用一个开关是否 onTouch 响应移位/缩放或绘制的路径。

 保护无效的OnDraw(帆布油画){
    如果(imgBitmap = NULL和放大器;!&安培;!帆布= NULL)
    {
        canvas.drawBitmap(imgBitmap,矩阵,背景);
        canvas.setMatrix(矩阵);
        的for(int i = 0; I< colors.size();我++){
            canvas.drawPath(paths.get(i)中,colors.get(ⅰ));
        }
        canvas.drawPath(drawPath,drawPaint);

    }
}
 

下面是一些图片和低于code休息:

 公共类ZoomImage扩展视图{
私有静态最后字符串变量=ZoomableImageView;

私人位图imgBitmap = NULL;

私人诠释containerWidth;
私人诠释containerHeight;

油漆背景;

//矩阵将用于移动和放大图像
字模=新的Matrix();
矩阵savedMatrix =新的Matrix();

的PointF开始=新的PointF();

浮动currentScale;
浮动CURX;
浮动CURY;

//我们可以在这3个状态之一
静态最终诠释无= 0;
静态最终诠释DRAG = 1;
静态最终诠释ZOOM = 2;
INT模式=无;

//对于动画的东西
浮动targetX;
浮动targetY;
浮动targetScale;
浮动targetScaleX;
浮动targetScaleY;
浮动scaleChange;
浮动targetRatio;
浮动transitionalRatio;

浮动缓和= 0.2F;
布尔isAnimating = FALSE;

浮scaleDampingFactor = 0.5F;

//对于捏和缩放
浮oldDist = 1F;
的PointF中期=新的PointF();

私人处理程序mHandler =新的处理程序();

浮动minScale;
浮maxScale = 3.0F;

浮wpRadius = 25.0f;
浮wpInnerRadius = 20.0f;

浮动screenDensity;

私人GestureDetector gestureDetector;

公共静态最终诠释DEFAULT_SCALE_FIT_INSIDE = 0;
公共静态最终诠释DEFAULT_SCALE_ORIGINAL = 1;

私人诠释defaultScale;


//绘制路径
私人路径drawPath;
//图纸和帆布油漆
市民漆drawPaint;
// 帆布
私人帆布drawCanvas;
//帆布位图
私人位图canvasBitmap;
//计数多少手指在屏幕上
INT pointerCount;
//检测捏放大活动
 //边界用于绘制路径时的放大
矩形clipBounds;
保存的路径//名单
 公众的ArrayList<路径>路径=新的ArrayList<路径>();
 保存颜色的//名单
 公众的ArrayList<油漆与GT;颜色=新的ArrayList<油漆与GT;();

 //创建路径和油漆绘制
公共无效setUpDrawing(){
    的System.out.println( -  setUpDrawing--);
    drawPath =新路径();
    drawPaint =新的油漆();

    drawPaint.setColor(Color.RED);
    drawPaint.setAntiAlias​​(真正的);
    drawPaint.setStrokeWidth(8);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap​​(Paint.Cap.ROUND);
}

公众诠释getDefaultScale(){
    返回defaultScale;
}

公共无效setDefaultScale(INT defaultScale){
    this.defaultScale = defaultScale;
}

公共ZoomImage(上下文的背景下){
    超(上下文);
    setFocusable(真正的);
    setFocusableInTouchMode(真正的);

    screenDensity = context.getResources()getDisplayMetrics()密度。

    initPaints();
    gestureDetector =新GestureDetector(新MyGestureDetector());
    setUpDrawing();
}

公共ZoomImage(上下文的背景下,ATTRS的AttributeSet){
    超(背景下,ATTRS);

    screenDensity = context.getResources()getDisplayMetrics()密度。
    initPaints();
    gestureDetector =新GestureDetector(新MyGestureDetector());

    defaultScale = ZoomImage.DEFAULT_SCALE_FIT_INSIDE;
    setUpDrawing();
}

私人无效initPaints(){
    背景=新的油漆();
    setUpDrawing();
}

@覆盖
保护无效onSizeChanged(INT宽度,高度INT,INT oldWidth,诠释oldHeight){
    super.onSizeChanged(宽度,高度,oldWidth,oldHeight);

    //重置的宽度和高度。将绘制位图和变化
    containerWidth =宽度;
    containerHeight =高度;

    如果(imgBitmap!= NULL){
        drawCanvas =新的Canvas(imgBitmap);
        INT imgHeight = imgBitmap.getHeight();
        INT imgWidth = imgBitmap.getWidth();

        浮规模;
        INT INITX = 0;
        INT inity这= 0;

        如果(defaultScale == ZoomImage.DEFAULT_SCALE_FIT_INSIDE){
            如果(imgWidth> containerWidth){
                规模=(浮点)containerWidth / imgWidth;
                浮newHeight = imgHeight *规模;
                inity这=(containerHeight  - (int)的newHeight)/ 2;

                matrix.setScale(秤,秤);
                matrix.postTranslate(0,inity这);
            }
            其他 {
                规模=(浮点)containerHeight / imgHeight;
                浮newWidth = imgWidth *规模;
                INITX =(containerWidth  - (int)的newWidth)/ 2;

                matrix.setScale(秤,秤);
                matrix.postTranslate(INITX,0);
            }

            CURX = INITX;
            CURY = inity这;

            currentScale =规模;
            minScale =规模;
        }
        其他 {
            如果(imgWidth> containerWidth){
                inity这=(containerHeight  - (int)的imgHeight)/ 2;
                matrix.postTranslate(0,inity这);
            }
            其他 {
                INITX =(containerWidth  - (int)的imgWidth)/ 2;
                matrix.postTranslate(INITX,0);
            }

            CURX = INITX;
            CURY = inity这;

            currentScale = 1.0F;
            minScale = 1.0F;
        }


        无效();
    }
}

@覆盖
保护无效的OnDraw(帆布油画){
    如果(imgBitmap = NULL和放大器;!&安培;!帆布= NULL)
    {
        canvas.drawBitmap(imgBitmap,矩阵,背景);
        canvas.setMatrix(矩阵);
        的for(int i = 0; I< colors.size();我++){
            canvas.drawPath(paths.get(i)中,colors.get(ⅰ));
        }
        canvas.drawPath(drawPath,drawPaint);

    }
}

公共无效reDrawUndo(){
    的System.out.println(paths.size+ paths.size());
     如果(paths.size()大于0){
         paths.remove(paths.size() -  1);
         colors.remove(colors.size() -  1);
         无效();
     }
}

//检查并设置目标图像的x和y坐标是否出界
私人无效checkImageConstraints(){
    如果(imgBitmap == NULL){
        返回;
    }

    浮动[] mvals =新的浮动[9];
    matrix.getValues​​(mvals);

    currentScale = mvals [0];

    如果(currentScale< minScale){
        浮deltaScale = minScale / currentScale;
        浮动PX = containerWidth / 2;
        浮PY = containerHeight / 2;
        matrix.postScale(deltaScale,deltaScale,PX,PY);
        无效();
    }

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


    布尔toMoveX = FALSE;
    布尔toMoveY = FALSE;

    如果(rangeLimitX℃,){
        如果(CURX大于0){
            targetX = 0;
            toMoveX =真;
        }
        否则,如果(CURX< rangeLimitX){
            targetX = rangeLimitX;
            toMoveX =真;
        }
    }
    其他 {
        targetX = rangeLimitX / 2;
        toMoveX =真;
    }

    如果(rangeLimitY℃,){
        如果(CURY大于0){
            targetY = 0;
            toMoveY =真;
        }
        否则,如果(CURY< rangeLimitY){
            targetY = rangeLimitY;
            toMoveY =真;
        }
    }
    其他 {
        targetY = rangeLimitY / 2;
        toMoveY =真;
    }

    如果(toMoveX ==真|| toMoveY ==真){
        如果(toMoveY = FALSE){
            targetY = CURY;
        }
        如果(toMoveX = FALSE){
            targetX = CURX;
        }

        //禁用触摸事件的行动
        isAnimating = TRUE;
        //初始化计时器
        mHandler.removeCallbacks(mUpdateImagePositionTask);
        mHandler.postDelayed(mUpdateImagePositionTask,100);
    }
}


@覆盖
公共布尔的onTouchEvent(MotionEvent事件){
    浮touchX = event.getX();
    的System.out.println(touchX:+ event.getX());
    浮敏感= event.getY();
    的System.out.println(棘手+ event.getY());

    //是上绘制模式?
    如果(Deal.on){
        开关(event.getAction()){
            案例MotionEvent.ACTION_DOWN:
                drawPath.moveTo(touchX,敏感);
                打破;
            案例MotionEvent.ACTION_MOVE:
                drawPath.lineTo(touchX,敏感);
                打破;
            案例MotionEvent.ACTION_UP:
                油漆newPaint =新的油漆();
                newPaint.set(drawPaint);
                colors.add(newPaint);
                paths.add(drawPath);
                drawPath =新路径();
                drawPath.reset();
                打破;
            案例MotionEvent.ACTION_POINTER_DOWN:
                的System.out.println(的Bleh);
                打破;
            默认:
                返回false;
        }
    }
    其他 {
        如果(gestureDetector.onTouchEvent(事件)){
            返回true;
        }

        如果(isAnimating ==真){
            返回true;
        }

        //这里处理触摸事件
        浮动[] mvals =新的浮动[9];
        开关(event.getAction()及MotionEvent.ACTION_MASK){
        案例MotionEvent.ACTION_DOWN:
            如果(isAnimating == FALSE){
                savedMatrix.set(矩阵);
                start.set(event.getX(),event.getY());
                模式=阻力;
            }
        打破;

        案例MotionEvent.ACTION_POINTER_DOWN:
            oldDist =间距(事件);
            如果(oldDist> 10F){
                savedMatrix.set(矩阵);
                中点(中,事件);
                模式=变焦;
            }
        打破;

        案例MotionEvent.ACTION_UP:
        案例MotionEvent.ACTION_POINTER_UP:
            模式=无;

            matrix.getValues​​(mvals);
            CURX = mvals [2];
            CURY = mvals [5];
            currentScale = mvals [0];

            如果(isAnimating == FALSE){
                checkImageConstraints();
            }
        打破;

        案例MotionEvent.ACTION_MOVE:
            如果(模式== DRAG&功放;&安培; isAnimating == FALSE){
                matrix.set(savedMatrix);
                浮diffX = event.getX() -  start.x;
                浮diffY = event.getY() -  start.y;

                matrix.postTranslate(diffX,diffY);

                matrix.getValues​​(mvals);
                CURX = mvals [2];
                CURY = mvals [5];
                currentScale = mvals [0];
            }
            否则,如果(模式==变焦和放大器;&安培; isAnimating == FALSE){
                浮newDist =间距(事件);
                如果(newDist> 10F){
                    matrix.set(savedMatrix);
                    浮规模= newDist / oldDist;
                    matrix.getValues​​(mvals);
                    currentScale = mvals [0];

                    如果(currentScale *规模< = minScale){
                        matrix.postScale(minScale / currentScale,minScale / currentScale,mid.x,mid.y);
                    }
                    否则,如果(currentScale *规模> = maxScale){
                        matrix.postScale(maxScale / currentScale,maxScale / currentScale,mid.x,mid.y);
                    }
                    其他 {
                        matrix.postScale(规模化,规模化,mid.x,mid.y);
                    }


                    matrix.getValues​​(mvals);
                    CURX = mvals [2];
                    CURY = mvals [5];
                    currentScale = mvals [0];
                }
            }

    打破;
    }
  }
    //计算的变换,然后无效
    无效();
    返回true;
}

私人浮动间距(MotionEvent事件){
    浮X = event.getX(0) -  event.getX(1);
    浮Y = event.getY(0) -  event.getY(1);
    返回FloatMath.sqrt(X * X + Y * Y);
}

私人无效中点(的PointF点,MotionEvent事件){
    浮X = event.getX(0)+ event.getX(1);
    浮Y = event.getY(0)+ event.getY(1);
    point.set(X / 2,Y / 2);
}

公共无效setImageBitmap(位图B){
    如果(B!= NULL){
        imgBitmap = B;

        containerWidth =的getWidth();
        containerHeight =的getHeight();

        INT imgHeight = imgBitmap.getHeight();
        INT imgWidth = imgBitmap.getWidth();

        浮规模;
        INT INITX = 0;
        INT inity这= 0;

        matrix.reset();

        如果(defaultScale == ZoomImage.DEFAULT_SCALE_FIT_INSIDE){
            如果(imgWidth> containerWidth){
                规模=(浮点)containerWidth / imgWidth;
                浮newHeight = imgHeight *规模;
                inity这=(containerHeight  - (int)的newHeight)/ 2;

                matrix.setScale(秤,秤);
                matrix.postTranslate(0,inity这);
            }
            其他 {
                规模=(浮点)containerHeight / imgHeight;
                浮newWidth = imgWidth *规模;
                INITX =(containerWidth  - (int)的newWidth)/ 2;

                matrix.setScale(秤,秤);
                matrix.postTranslate(INITX,0);
            }

            CURX = INITX;
            CURY = inity这;

            currentScale =规模;
            minScale =规模;
        }
        其他 {
            如果(imgWidth> containerWidth){
                INITX = 0;
                如果(imgHeight> containerHeight){
                    inity这= 0;
                }
                其他 {
                    inity这=(containerHeight  - (int)的imgHeight)/ 2;
                }

                matrix.postTranslate(0,inity这);
            }
            其他 {
                INITX =(containerWidth  - (int)的imgWidth)/ 2;
                如果(imgHeight> containerHeight){
                    inity这= 0;
                }
                其他 {
                    inity这=(containerHeight  - (int)的imgHeight)/ 2;
                }
                matrix.postTranslate(INITX,0);
            }

            CURX = INITX;
            CURY = inity这;

            currentScale = 1.0F;
            minScale = 1.0F;
        }

        无效();
    }
    其他 {
        Log.d(TAG,位为空);
    }
}

公共位图getPhotoBitmap(){
    返回imgBitmap;
}


私人可运行mUpdateImagePositionTask =新的Runnable(){
    公共无效的run(){
        浮动[] mvals;

        如果(Math.abs(targetX  -  CURX)小于5&安培;&安培; Math.abs(targetY  -  CURY)小于5){
            isAnimating = FALSE;
            mHandler.removeCallbacks(mUpdateImagePositionTask);

            mvals =新的浮动[9];
            matrix.getValues​​(mvals);

            currentScale = mvals [0];
            CURX = mvals [2];
            CURY = mvals [5];

            //设置图像参数和失效显示
            浮动diffX =(targetX  -  CURX);
            浮动diffY =(targetY  -  CURY);

            matrix.postTranslate(diffX,diffY);
        }
        其他 {
            isAnimating = TRUE;
            mvals =新的浮动[9];
            matrix.getValues​​(mvals);

            currentScale = mvals [0];
            CURX = mvals [2];
            CURY = mvals [5];

            //设置图像参数和失效显示
            浮动diffX =(targetX  -  CURX)* 0.3f;
            浮动diffY =(targetY  -  CURY)* 0.3f;

            matrix.postTranslate(diffX,diffY);
            mHandler.postDelayed(这一点,25);
        }

        无效();
    }
};

私人可运行mUpdateImageScale =新的Runnable(){
    公共无效的run(){
        浮transitionalRatio = targetScale / currentScale;
        浮动DX;
        如果(Math.abs(transitionalRatio  -  1)> 0.05){
            isAnimating = TRUE;
            如果(targetScale> currentScale){
                DX = transitionalRatio  -  1;
                scaleChange = 1 + DX * 0.2F;

                currentScale * = scaleChange;

                如果(currentScale> targetScale){
                    currentScale = currentScale / scaleChange;
                    scaleChange = 1;
                }
            }
            其他 {
                DX = 1  -  transitionalRatio;
                scaleChange = 1  -  DX * 0.5F;
                currentScale * = scaleChange;

                如果(currentScale< targetScale){
                    currentScale = currentScale / scaleChange;
                    scaleChange = 1;
                }
            }


            如果(scaleChange!= 1){
                matrix.postScale(scaleChange,scaleChange,targetScaleX,targetScaleY);
                mHandler.postDelayed(mUpdateImageScale,15);
                无效();
            }
            其他 {
                isAnimating = FALSE;
                scaleChange = 1;
                matrix.postScale(targetScale / currentScale,targetScale / currentScale,targetScaleX,targetScaleY);
                currentScale = targetScale;
                mHandler.removeCallbacks(mUpdateImageScale);
                无效();
                checkImageConstraints();
            }
        }
        其他 {
            isAnimating = FALSE;
            scaleChange = 1;
            matrix.postScale(targetScale / currentScale,targetScale / currentScale,targetScaleX,targetScaleY);
            currentScale = targetScale;
            mHandler.removeCallbacks(mUpdateImageScale);
            无效();
            checkImageConstraints();
        }
    }
};

类MyGestureDetector扩展SimpleOnGestureListener {
    @覆盖
    公共布尔onDoubleTap(MotionEvent事件){
        如果(isAnimating ==真){
            返回true;
        }

        scaleChange = 1;
        isAnimating = TRUE;
        targetScaleX = event.getX();
        targetScaleY = event.getY();

        如果(Math.abs(currentScale  -  maxScale)GT; 0.1){
            targetScale = maxScale;
        }
        其他 {
            targetScale = minScale;
        }
        targetRatio = targetScale / currentScale;
        mHandler.removeCallbacks(mUpdateImageScale);
        mHandler.post(mUpdateImageScale);
        返回true;
    }

    @覆盖
    公共布尔onFling(MotionEvent E1,E2 MotionEvent,浮velocityX,浮velocityY){
        返回super.onFling(E1,E2,velocityX,velocityY);
    }

    @覆盖
    公共布尔onDown(MotionEvent E){
        返回false;
    }
}
 

}

编辑: 添加 canvas.concat(矩阵)固定变焦。还是试图修复抵消...

OnDraw中更改为:

  super.onDraw(画布);
    canvas.save();
    如果(imgBitmap = NULL和放大器;!&安培;!帆布= NULL){
        如果(drawCanvas == NULL)
            drawCanvas =新的Canvas(imgBitmap);

        clipBounds = canvas.getClipBounds();
        canvas.drawBitmap(imgBitmap,矩阵,背景);
        canvas.concat(矩阵);
        的for(int i = 0; I< colors.size();我++){
            canvas.drawPath(paths.get(i)中,colors.get(ⅰ));
        }
        canvas.drawPath(drawPath,drawPaint);

    }
    canvas.restore();
    无效();
 

解决方案

明白了!获取规模矩阵值和偏移,调整touchX和敏感的相应。 MV [4]是规模的同时,mv的[2]和mv [5]是在x和y的偏移量,分别

 浮法[] MV =新的浮动[9];

@覆盖
公共布尔的onTouchEvent(MotionEvent事件){

    //从矩阵值到float数组
    matrix.getValues​​(MV);

    浮touchX =(event.getX()*(1 / MV [4]) - (MV [2] / MV [4]));
    浮敏感=(event.getY()*(1 / MV [4]) - (MV [5] / MV [4]));
 

I'm implementing a zoomable View from examples I've found on Stack and other websites. I do want to add a drawing feature to the view. I'm able to get the paths to show up but the scaling is way off from the image behind it. I used an example android image where I traced along the shape and the paths appeared to the left and above it. Also, zooming causes it to shift (pictures below).

I've been playing around with the onDraw method where the canvas is drawn but with little success. I basically use a switch whether the onTouch responds to shifting/zooming or drawing the paths.

protected void onDraw(Canvas canvas) {               
    if(imgBitmap != null && canvas != null)
    {                            
        canvas.drawBitmap(imgBitmap, matrix, background);
        canvas.setMatrix(matrix);
        for (int i = 0; i < colors.size(); i++) {
            canvas.drawPath(paths.get(i), colors.get(i));
        }
        canvas.drawPath(drawPath, drawPaint);

    }
}

Here are the pictures and rest of code below:

public class ZoomImage 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 = 3.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;


// Drawing path
private Path drawPath;
// Drawing and canvas paint
public Paint drawPaint;
// Canvas
private Canvas drawCanvas;
// Canvas bitmap
private Bitmap canvasBitmap;
// Counts how many fingers are on the screen
int pointerCount;
// Detects pinch to zoom activity
 // Bounds used to draw paths when zoomed in
Rect clipBounds;
// List of saved paths
 public ArrayList<Path> paths = new ArrayList<Path>();
 // List of saved colors
 public ArrayList<Paint> colors = new ArrayList<Paint>();

 // Creates Path and Paint for drawing
public void setUpDrawing() {
    System.out.println("--setUpDrawing--");
    drawPath = new Path();
    drawPaint = new Paint();

    drawPaint.setColor(Color.RED);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(8);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);
}

public int getDefaultScale() {
    return defaultScale;
}

public void setDefaultScale(int defaultScale) {
    this.defaultScale = defaultScale;
}

public ZoomImage(Context context) {
    super(context);       
    setFocusable(true);
    setFocusableInTouchMode(true);

    screenDensity = context.getResources().getDisplayMetrics().density;

    initPaints();
    gestureDetector = new GestureDetector(new MyGestureDetector());    
    setUpDrawing();
}

public ZoomImage(Context context, AttributeSet attrs) {
    super(context, attrs);

    screenDensity = context.getResources().getDisplayMetrics().density;       
    initPaints();
    gestureDetector = new GestureDetector(new MyGestureDetector());

    defaultScale = ZoomImage.DEFAULT_SCALE_FIT_INSIDE;
    setUpDrawing();
}

private void initPaints() {
    background = new Paint();
    setUpDrawing();
}

@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) {
        drawCanvas = new Canvas(imgBitmap);
        int imgHeight = imgBitmap.getHeight();
        int imgWidth = imgBitmap.getWidth();

        float scale;
        int initX = 0;
        int initY = 0;           

        if(defaultScale == ZoomImage.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);
        canvas.setMatrix(matrix);
        for (int i = 0; i < colors.size(); i++) {
            canvas.drawPath(paths.get(i), colors.get(i));
        }
        canvas.drawPath(drawPath, drawPaint);

    }
}

public void reDrawUndo() {
    System.out.println("paths.size" + paths.size());
     if (paths.size() > 0) {
         paths.remove(paths.size() - 1);
         colors.remove(colors.size() - 1);
         invalidate();
     }
}

//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) {  
    float touchX = event.getX();
    System.out.println("touchX: " + event.getX());
    float touchY = event.getY();
    System.out.println("touchY: " + event.getY());

    // Is drawing mode on?
    if (Deal.on){
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                drawPath.moveTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                drawPath.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                Paint newPaint = new Paint();
                newPaint.set(drawPaint);
                colors.add(newPaint);
                paths.add(drawPath);
                drawPath = new Path();
                drawPath.reset();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                System.out.println("bleh");
                break;
            default:
                return false;
        }
    }
    else {
        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 == ZoomImage.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();
        }                               
    }
};

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

}

EDIT: Adding canvas.concat(matrix) fixed the zooming. Still trying to fix the offset...

onDraw changed to:

    super.onDraw(canvas);
    canvas.save();
    if(imgBitmap != null && canvas != null){     
        if(drawCanvas == null)
            drawCanvas = new Canvas(imgBitmap);

        clipBounds = canvas.getClipBounds();
        canvas.drawBitmap(imgBitmap, matrix, background);
        canvas.concat(matrix);
        for (int i = 0; i < colors.size(); i++) {
            canvas.drawPath(paths.get(i), colors.get(i));
        }
        canvas.drawPath(drawPath, drawPaint);

    }
    canvas.restore();
    invalidate();

解决方案

Got it! Get the matrix values for scale and offset and adjust the touchX and touchY accordingly. mv[4] is the scale, while mv[2] and mv[5] are the offsets in x and y, respectively.

float[] mv = new float[9];

@Override
public boolean onTouchEvent(MotionEvent event) {

    // Get the values from the matrix into the float array
    matrix.getValues(mv);

    float touchX = (event.getX()*(1/mv[4]) - (mv[2]/mv[4]));
    float touchY = (event.getY()*(1/mv[4]) - (mv[5]/mv[4]));

这篇关于ZOOMVIEW帆布矩阵的Andr​​oid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆