Android画布在放大时带边界滚动

Android画布在放大时带边界滚动,android,android-canvas,Android,Android Canvas,我有一个画布,我可以缩小和滚动边界,代码在这里 package com.mypackage.ui.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import

我有一个画布,我可以缩小和滚动边界,代码在这里

package com.mypackage.ui.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.provider.SyncStateContract;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 *
 */
public class MyDrawingView extends View {

    private static final int INVALID_POINTER_ID = -1;

    private int state = 0; //0 se dibuja - 1 se mueve

    //drawing path
    private Path drawPath;
    //drawing and canvas paint
    private Paint drawPaint, canvasPaint;

    //canvas
    private Canvas drawCanvas;
    //canvas bitmap
    private Bitmap bitmap;

    protected String tool;
    protected String color;
    protected float brushSize;

    //erase flag
    private boolean erase=false;

    public String getTool() {
        return tool;
    }

    public void setTool(String tool) {
        this.tool = tool;
    }

    public String getColor() {
        return color;
    }

    public float getBrushSize() {
        return brushSize;
    }

    public boolean isErase() {
        return erase;
    }

    private String drawId;

//    public OnSaveActionListener listener;

    private float mPosX;
    private float mPosY;

    public float getMPosX() { return mPosX; }

    public float getMPosY() { return mPosY; }

    private float mLastTouchX;
    private float mLastTouchY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    private float viewHeight;
    private float viewWidth;
    float canvasWidth, canvasHeight;

    private float minScaleFactor;

    private boolean panEnabled = true;
    private boolean zoomEnabled = true;

    public MyDrawingView(Context context) {
        super(context);
        setup();
    }

    public MyDrawingView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setup();
    }

    public MyDrawingView(Context context, AttributeSet attrs){
        super(context, attrs);
        setup();
    }

    //setup drawing
    private void setup(){
        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
        //prepare for drawing and setup paint stroke properties
        drawPath = new Path();
        drawPaint = new Paint();
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);
        canvasPaint = new Paint(Paint.DITHER_FLAG);
    }

    public void setState(int state) {

        this.state = state;

    }

    public void setImageBitmap(Bitmap bmp) {
        bitmap = bmp;
        resetZoom();
        resetPan();
        invalidate();
    }

    public void setImageDrawable(Drawable drawable) {
        setImageBitmap(((BitmapDrawable) drawable).getBitmap());
    }

    public void setBitmap(Bitmap bmp) {
        setImageBitmap(bmp);
    }

    public void resetZoom() {
        mScaleFactor = 1.0f;
    }

    public void resetPan() {
        mPosX = 0f;
        mPosY = 0f;
    }

    public BitmapDrawable getImageDrawable() {
        BitmapDrawable bd = new BitmapDrawable(getContext().getResources(), bitmap);
        return bd;
    }

    public BitmapDrawable getDrawable() {
        return getImageDrawable();
    }

    //size assigned to view
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(bitmap);
    }

    //draw the view - will be called after touch event
    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        mScaleFactor = Math.max(mScaleFactor, minScaleFactor);

        canvasHeight = canvas.getHeight();
        canvasWidth = canvas.getWidth();

        //Save the canvas without translating (panning) or scaling (zooming)
        //After each change, restore to this state, instead of compounding
        //changes upon changes
        canvas.save();
        int maxX, minX, maxY, minY;
        //Regardless of the screen density (HDPI, MDPI) or the scale factor,
        //The image always consists of bitmap width divided by 2 pixels. If an image
        //is 200 pixels wide and you scroll right 100 pixels, you just scrolled the image

        //off the screen to the left.
        minX = (int) (((viewWidth / mScaleFactor) - bitmap.getWidth()) / 2);
        maxX = 0;
        //How far can we move the image vertically without having a gap between image and frame?
        minY = (int) (((viewHeight / mScaleFactor) - bitmap.getHeight()) / 2);
        maxY = 0;
        //Do not go beyond the boundaries of the image
        if (mPosX > maxX) {
            mPosX = maxX;
        }
        if (mPosX < minX) {
            mPosX = minX;
        }
        if (mPosY > maxY) {
            mPosY = maxY;
        }
        if (mPosY < minY) {
            mPosY = minY;
        }

        if (state == 0) {
        } else if (state == 1) {
            canvas.scale(this.mScaleFactor, this.mScaleFactor, this.mScaleDetector.getFocusX(), this.mScaleDetector.getFocusY());
        }

        canvas.translate(mPosX, mPosY);
        canvas.drawBitmap(bitmap, 0, 0, canvasPaint);
        canvas.drawPath(drawPath, drawPaint);
        canvas.restore();
        invalidate();
    }

    //register user touches as drawing action
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        mScaleDetector.onTouchEvent(event);

        float touchX = event.getX();
        float touchY = event.getY();

        if(isErase()){
            drawCanvas.drawPath(drawPath, drawPaint);
            invalidate();
        }

        //respond to down, move and up events
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mLastTouchX = touchX;
                mLastTouchY = touchY;
                mActivePointerId = event.getPointerId(0);

                break;
            case MotionEvent.ACTION_MOVE:

                if (state == 0) {
                } else if (state == 1) {

                    final int pointerIndex = event.findPointerIndex(mActivePointerId);
                    final float x = event.getX(pointerIndex);
                    final float y = event.getY(pointerIndex);

                    // Only move if the ScaleGestureDetector isn't processing a gesture.
                    if (!mScaleDetector.isInProgress()) {
                        final float dx = x - mLastTouchX;
                        final float dy = y - mLastTouchY;

                        mPosX += dx;
                        mPosY += dy;

                        invalidate();
                    }

                    mLastTouchX = x;
                    mLastTouchY = y;

                }
                break;
            case MotionEvent.ACTION_UP:
                mActivePointerId = INVALID_POINTER_ID;

                break;

            case MotionEvent.ACTION_CANCEL:
                mActivePointerId = INVALID_POINTER_ID;
                break;

            case MotionEvent.ACTION_POINTER_UP:
                final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = event.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = event.getX(newPointerIndex);
                    mLastTouchY = event.getY(newPointerIndex);
                    mActivePointerId = event.getPointerId(newPointerIndex);
                }
                break;

            default:
                return false;
        }

        return true;

    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));

            invalidate();
            return true;
        }
    }



}
package com.mypackage.ui.view;
导入android.content.Context;
导入android.graphics.Bitmap;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.Path;
导入android.graphics.PorterDuff;
导入android.graphics.PorterDuffXfermode;
导入android.graphics.Rect;
导入android.graphics.drawable.BitmapDrawable;
导入android.graphics.drawable.drawable;
导入android.provider.SyncStateContract;
导入android.util.AttributeSet;
导入android.util.Log;
导入android.util.TypedValue;
导入android.view.MenuItem;
导入android.view.MotionEvent;
导入android.view.scalegestruedetector;
导入android.view.view;
导入java.text.simpleDataFormat;
导入java.util.Date;
导入java.util.List;
导入java.util.Locale;
/**
*
*/
公共类MyDrawingView扩展视图{
私有静态final int无效\u指针\u ID=-1;
私有int state=0;//0 se dibuja-1 se mueve
//绘图路径
专用路径;
//绘画和油画
私人油漆拉丝漆、帆布漆;
//帆布
私人帆布;
//画布位图
私有位图;
保护管柱工具;
保护字符串颜色;
受保护的浮刷尺寸;
//擦除标志
私有布尔擦除=假;
公共字符串getTool(){
返回工具;
}
公共无效设置工具(字符串工具){
这个工具=工具;
}
公共字符串getColor(){
返回颜色;
}
公共浮点数getBrushSize(){
回刷尺寸;
}
公共布尔isErase(){
返回擦除;
}
私有字符串drawId;
//公众参与;听众参与;
私人浮动mPosX;
私家车;
公共浮点getMPosX(){return mPosX;}
公共浮点getMPosY(){return mPosY;}
私有浮动mLastTouchX;
私密的浮躁和敏感;
private int mActivePointerId=无效的\u指针\u ID;
专用scalegestruedetector mScaleDetector;
私人浮动mScaleFactor=1.f;
私家浮动高度;
私有浮动视宽;
浮动画布宽度、画布高度;
私人浮动因素;
private boolean panEnabled=true;
私有布尔zoomEnabled=true;
公共MyDrawingView(上下文){
超级(上下文);
设置();
}
公共MyDrawingView(上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
设置();
}
公共MyDrawingView(上下文、属性集属性){
超级(上下文,attrs);
设置();
}
//安装图
私有无效设置(){
mScaleDetector=新的ScaleGetDetector(getContext(),new ScaleListener());
//准备绘制并设置绘制笔划特性
drawPath=新路径();
drawPaint=新油漆();
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(绘制.连接.圆形);
drawPaint.setStrokeCap(油漆盖圆形);
画布绘制=新绘制(绘制抖动标志);
}
公共无效设置状态(int状态){
this.state=状态;
}
公共void setImageBitmap(位图bmp){
位图=bmp;
重置缩放();
resetPan();
使无效();
}
公共void setImageDrawable(可提取可提取){
setImageBitmap(((BitmapDrawable)drawable.getBitmap());
}
公共void setBitmap(位图bmp){
setImageBitmap(bmp);
}
公共void resetZoom(){
mScaleFactor=1.0f;
}
公共无效重置PAN(){
mPosX=0f;
mPosY=0f;
}
公共BitmapDrawable getImageDrawable(){
BitmapDrawable bd=新的BitmapDrawable(getContext().getResources(),位图);
返回bd;
}
公共BitmapDrawable getDrawable(){
返回getImageDrawable();
}
//指定给视图的大小
@凌驾
已更改尺寸的受保护空心(整数w、整数h、整数oldw、整数oldh){
super.onSizeChanged(w,h,oldw,oldh);
bitmap=bitmap.createBitmap(w,h,bitmap.Config.ARGB_8888);
drawCanvas=新画布(位图);
}
//绘制视图-将在触摸事件后调用
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);
mScaleFactor=Math.max(mScaleFactor,minScaleFactor);
canvasHeight=canvas.getHeight();
canvasWidth=canvas.getWidth();
//保存画布而不平移(平移)或缩放(缩放)
//每次更改后,恢复到此状态,而不是复合
//变化无常
canvas.save();
int maxX,minX,maxY,minY;
//无论屏幕密度(HDPI、MDPI)或比例因子,
//图像总是由位图宽度除以2像素组成。如果图像
//是200像素宽,你向右滚动100像素,你只需滚动图像
//在屏幕左侧。
minX=(int)((viewWidth/mScaleFactor)-bitmap.getWidth())/2);
maxX=0;
//在图像和帧之间没有间隙的情况下,我们可以垂直移动图像多远?
minY=(int)((viewHeight/mScaleFactor)-bitmap.getHeight())/2);
maxY=0;
//不要超出图像的边界
如果(mPosX>maxX){
mPosX=maxX;
}
if(mPosX最大值){
mPosY=maxY;
}
if(mPosY