Android 之dialog 以及界面设计规则,画板项目需求分析,变换画线Path 大小 长度Canvase变换

  dialog.setContentView(getView());
        Window window  = dialog.getWindow();
          WindowManager.LayoutParams lp = window.getAttributes();
          lp.width = 200;
          lp.height = 200;
          window.setAttributes(lp);

        // window.setLayout(200,200); 等价
界面设计简洁化

1.去除无用的功能(研究发现:80%的用户仅仅使用软件20%的功能。)
2.隐藏复杂部分
3.最小化视觉干扰
4.做减法、重复使用,循环利用
5.空白状态不应空白

2015-05-16

画板项目更新

需求分析:
1.画笔,颜色,大小
2.橡皮檫,清屏
3.放大,缩小
4.保存图片
5.更改(恢复,撤销)
6.拖拽(拖动画板)
7.剪切(+移动)
8.加页

1.创建画笔

    mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);//画笔样式
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setDither(true);//是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰  
        mPaint.setStrokeWidth(画笔大小);
        mPaint.setColor(设置颜色);

3.图片放大缩小


    /**
     *  
     * new Bitmap 变换矩阵
     */
    private Bitmap scaleBitmap(Bitmap origin, float scale) {
        if (origin == null) {
            return null;
        }
        int height = origin.getHeight() > screenHeight * 2 ? (int) (screenHeight * 2) : origin.getHeight();
        int width = origin.getWidth() > screenWidth * 2 ? (int) (screenWidth * 2) : origin.getWidth();
         Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, true);
        if (!origin.isRecycled()) {
            origin.recycle();
        }
        return newBM;
    }
  public void changePaint(float scale) {

//        float stroke = mPaint.getStrokeWidth();
        tempPath.addAll(savePath);
        initCanvas();
        savePath.clear();
        deletePath.clear();

        mPaint.setStrokeWidth(mPaint.getStrokeWidth() * scale);
        for (int i = 0; i < tempPath.size(); i++) {
            dp = new DrawPath();
            dp.path = tempPath.get(i).path;
            dp.paint = tempPath.get(i).paint;
            dp.paint.setStrokeWidth(dp.paint.getStrokeWidth() * scale > 50 ? 50 : dp.paint.getStrokeWidth() * scale < 1 ? 1 : dp.paint.getStrokeWidth() * scale);
            mCanvas.drawPath(dp.path, dp.paint);
            savePath.add(dp);

        }
        invalidate();
//        mPaint.setStrokeWidth(stroke);
    }

在这场画线变化中 也有不少思量,本以为是一件不过平常的事情 后来发现实践的困难度远高于理论,何况理论还不一定正确,线段变换,最终我的思路是重新画 ,把之前画的摸出掉 重新画线把path这个路径缩小 ,你很快发现路径缩小了 线段大小缩小了 然而宽度依然不变这就有必要存储paint 画笔了
变化代码 目前已屏幕为中心改变大小

  public void changePath(float scale) {

        DrawPath drawPath = savePath.get(0);
        Path path = drawPath.getPath();

        float currentWidth = drawPath.getStrokeWidth();
        float scaleStrokeWidth = currentWidth * scale;

        //计算中心点

        Matrix matrix = new Matrix();
        matrix.setScale(scale, scale, (int) screenWidth / 2, (int) screenHeight / 2);
        path.transform(matrix);

        drawPath.setStrokeWidth(scaleStrokeWidth);
        drawPath.setPath(path);
        savePath.set(0, drawPath);
        initCanvas();

        Iterator<DrawPath> it = savePath.iterator();
        while (it.hasNext()) {
            DrawPath drawPath1 = it.next();
            mPaint.setStrokeWidth(drawPath1.getStrokeWidth());
            mPaint.setColor(drawPath1.getPaintColor());
            mCanvas.drawPath(drawPath1.getPath(), mPaint);


        }

        invalidate();
    }

计算中心点变换 我以为记录首尾坐标就行了 可是你要是遇到闭环圆画线中心点又在哪里,我按外接矩形来做

public class DrawPath {
    private Path path;

    public PointF getStartPoint() {
        return startPoint;
    }

    public void setStartPoint(PointF startPoint) {
        this.startPoint = startPoint;
    }

    public PointF getEndPoint() {
        return endPoint;
    }

    public void setEndPoint(PointF endPoint) {
        this.endPoint = endPoint;
    }

    private PointF startPoint;

    private PointF endPoint;
    private float strokeWidth;
    private int PaintColor;


    //    private Paint paint;
    public float getStrokeWidth() {
        return strokeWidth;
    }

    public void setStrokeWidth(float strokeWidth) {
        this.strokeWidth = strokeWidth;
    }

    public int getPaintColor() {
        return PaintColor;
    }

    public void setPaintColor(int paintColor) {
        PaintColor = paintColor;
    }


    public Path getPath() {
        return path;
    }

    public void setPath(Path path) {
        this.path = path;
    }
    }

这里写图片描述

OOM 处理

 java.lang.OutOfMemoryError: Failed to allocate a 15736332 byte allocation with 3336656 free bytes and 3MB until OOM
                                                                                  at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
       //缩放模式
                if (mode == LOCKED && (!savePath.isEmpty())) {
                    Toast.makeText(context, "进入缩放模式", Toast.LENGTH_SHORT).show();
                    PathEffect pathEffect = mPaint.getPathEffect();

                    for (int i = 0; i < savePath.size(); i++) {
                        DrawPath drawPath = savePath.get(i);
                        Path a = drawPath.getPath();
                        RectF rectf = new RectF();
                        a.computeBounds(rectf, false);
                        mPaint.setColor(Color.BLUE);
                        Region region = new Region((int) rectf.left, (int) rectf.top, (int) rectf.right, (int) rectf.bottom);

                        if (region.contains((int) event.getX(), (int) event.getY())) {
                            drawPath.setSelected(true);
                            PathEffect effects = new DashPathEffect(new float[]{25, 15, 25, 15}, 1);
                            mPaint.setPathEffect(effects);
                            mCanvas.drawRect(rectf, mPaint);
//                            Log.e("", "--判断点是否则范围内----" + region.contains((int) event.getX(), (int) event.getY()));
                            invalidate();
                        }
                        mPaint.setPathEffect(pathEffect);
                    }

                }

2017-06-14

画板移动:任意移动

package com.example.myapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Xfermode;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Project_name: MyApplication2
 * Date: 2017/3/2511:09
 * Email: xiaoxilong5201314@163.com.
 * Author: Aaron Empire
 * Description: TODO
 */


public class FunctionView extends View {


    public static final String TAG = "MultifunctionView";
    private Context context;
    private Bitmap mBitmap;
    private Canvas mCanvas, mpCanvas;
    private Path mPath;
    private Paint mBitmapPaint, mPaint;
    private float mX, mY;
    public static final float TOUCH_TOLERANCE = 4;
    private float centerX;
    private float centerY;
    private Paint mp;
    private float scaleX;
    private float scaleY;

    public static List<DrawPath> getSavePath() {
        return savePath;
    }

    public static void setSavePath(List<DrawPath> savePath) {
        FunctionView.savePath = savePath;
    }

    public static List<DrawPath> getDeletePath() {
        return deletePath;
    }

    public static void setDeletePath(List<DrawPath> deletePath) {
        FunctionView.deletePath = deletePath;
    }

    private static List<DrawPath> savePath;
    private static List<DrawPath> deletePath;
    private static List<DrawPath> tempPath;

    private DrawPath dp;
    private double screenWidth, screenHeight;
    private int currentColor = Color.RED;
    //    private int currentColor = 0x55ff0000;
    private float currentSize = 15;
    private int currentStyle = 1;
    private int[] paintColor;
    private PathMeasure pathMeasure;
    private Xfermode defaultMode;
    private int paintalpha;


    int mode = NONE;// 1为一个触摸点,2为两个触摸点
    static final int NONE = 0; //划线的指令
    static final int DRAG = 1;//拖拽指令
    static final int ZOOM = 2;//缩放指令
    static final int LOCKED = 3;//锁定Path,并绘制
    static final int CLEAN = 4;//  擦除模式
    int saveMode = mode;
    //缩放部分
    float oldDist = 1f;
    private float newDist;
    private float startX, startY;
    private float mScaleX = 4 / 3, mTranslateX, mTranslateY, mScaleY = 4 / 3;

    public FunctionView(Context context, int w, int h) {
        super(context);
        this.context = context;
        screenHeight = h;
        screenWidth = w;

        //六种颜色
        paintColor = new int[]{Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK, Color.GRAY, Color.CYAN, Color.TRANSPARENT};
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        initCanvas();
        savePath = new ArrayList<>();
        deletePath = new ArrayList<>();
        tempPath = new ArrayList<>();
        pathMeasure = new PathMeasure();


    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mode == NONE) {

            Rect src = new Rect((int) (mTranslateX + scaleX), (int) (mTranslateY + scaleY), (int) (mTranslateX * 3 + scaleX), (int) (mTranslateY * 3 + scaleY));
            RectF dest = new RectF(0, 0, (float) screenWidth, (float) screenHeight);
            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }
        if (mode == DRAG) {
            Rect src = new Rect((int) (mTranslateX + scaleX), (int) (mTranslateY + scaleY), (int) (mTranslateX * 3 + scaleX), (int) (mTranslateY * 3 + scaleY));
            RectF dest = new RectF(0, 0, (float) screenWidth, (float) screenHeight);
            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }
        if (mPath != null) {
            canvas.drawPath(mPath, mPaint);
        }
    }


    private void initCanvas() {
        setPaintStyle();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        mBitmap = Bitmap.createBitmap((int) screenWidth * 2, (int) screenHeight * 2, Bitmap.Config.ARGB_8888);
        mBitmap.eraseColor(Color.argb(255, 255, 255, 0));
        mCanvas = new Canvas(mBitmap);
        mCanvas.translate((int) (screenWidth / 2 + scaleX), (int) (screenHeight / 2 + scaleY));
        mTranslateX = (int) (screenWidth / 2 + scaleX);
        mTranslateY = (int) (screenHeight / 2 + scaleY);
    }

    private void setPaintStyle() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        defaultMode = mPaint.getXfermode();
        paintalpha = mPaint.getAlpha();
        if (currentStyle == 1) {
            mPaint.setStrokeWidth(currentSize);
            mPaint.setColor(currentColor);
        } else {
            //橡皮模式

            mPaint.setAlpha(0);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
            mPaint.setColor(Color.TRANSPARENT);
            mPaint.setStrokeWidth(50);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        startX = event.getX();
        startY = event.getY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:

                //画图模式
                if (mode == NONE) {
                    if (currentStyle == 1) {
                        //回复原状
                        mPaint.setColor(currentColor);
                        mPaint.setStrokeWidth(currentSize);
                    }


                    // 每次down下去重新new一个Path
                    mPath = new Path();
                    //每一次记录的路径对象是不一样的
                    dp = new DrawPath();
                    dp.setPath(mPath);
                    dp.setStrokeWidth(mPaint.getStrokeWidth());
                    dp.setPaintColor(mPaint.getColor());
                    touch_start(startX, startY);
                    invalidate();
                }


                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (event.getPointerCount() == 3) {
                    mode = DRAG;

                    centerX = event.getX(0);
                    centerY = event.getY(0);


                }

                break;
            case MotionEvent.ACTION_POINTER_UP:

                break;
            case MotionEvent.ACTION_MOVE:
                if (event.getPointerCount() == 2) {
                    newDist = getDistance(event);
                }
                if (mode == NONE) {
                    touch_move(startX, startY);
                    invalidate();
                    if (currentStyle == 2) {
                    }
                }

                if (mode == DRAG) {
//                    if (Math.abs(event.getX(0) - centerX) > Math.abs(event.getY(0) - centerY)) {
//                        //执行x 轴拖动
                        scaleX = scaleX + (centerX - event.getX(0)) / 4;
                        mCanvas.translate((centerX - event.getX(0)) / 4, 0);
//
//                        scaleX = scaleX + (centerX - event.getX(0))  ;
//                        mCanvas.translate((centerX - event.getX(0)) , 0);
//                    } else {
//                        //执行y 轴拖动
                        scaleY = scaleY + (centerY - event.getY(0)) / 6;
                        mCanvas.translate(0, (centerY - event.getY(0)) / 6);
//
//                        scaleY = scaleY + (centerY - event.getY(0)) ;
//                        mCanvas.translate(0, (centerY - event.getY(0)) );
//                    }
                    scaleX = scaleX + (centerX - event.getX(0))  ;
                    scaleY = scaleY + (centerY - event.getY(0)) ;

                    mCanvas.translate((centerX - event.getX(0)), (centerY - event.getY(0)) );

                    invalidate();

                }

                centerX = event.getX(0);
                centerY = event.getY(0);
                break;
            case MotionEvent.ACTION_UP:
                if (mode == NONE) {
                    touch_up();
                    invalidate();
                    mode = NONE;
                }
                mode = NONE;


                break;
        }
        return true;
    }

    /**
     * 图片缩放,拖拽,部分方法
     */
    private float getDistance(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    /**
     * 划线部分操作
     */
    private void touch_start(float x, float y) {
        //初始化path点
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        //存起点
        PointF startPoint = new PointF();
        startPoint.set(x, y);
        dp.setStartPoint(startPoint);

        mCanvas.drawPath(mPath, mPaint);
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(mY - y);
        //两点间距离大于4 生成贝塞尔曲线
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            //贝塞尔曲线mX, mY为控制点  (x + mX) / 2, (y + mY) / 2 为终点
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;

            mCanvas.drawPath(mPath, mPaint);
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        PathMeasure pathMeasure = new PathMeasure(mPath, false);
        int length = (int) pathMeasure.getLength();


        if (length != 0) {
            //存尾点
            PointF startPoint = new PointF();
            startPoint.set(mX, mY);
            dp.setEndPoint(startPoint);
            //绘制整个平滑的线条
            //存Path 区域
            dp.setRegion(savePathRegion(mPath));
            dp.setXfermode(mPaint.getXfermode());
            dp.setPaintalpha(mPaint.getAlpha());
            mCanvas.drawPath(mPath, mPaint);
            savePath.add(dp);
            mPath = null;
            dp = null;

        } 


    }



    /**
     * 保存图片
     *
     * @param bitName
     * @param mBitmap
     * @return
     */
    public static String saveBitmap(String bitName, Bitmap mBitmap) {


        File f = new File("/sdcard/" + bitName + ".png");

        try {
            f.createNewFile();
        } catch (IOException e) {
            System.out.println("在保存图片时出错:" + e.toString());
        }
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
        } catch (Exception e) {
            return "create_bitmap_error";
        }
        try {
            fOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "/sdcard/" + bitName + ".png";
    }

    // 存Path 区域对象Region
    public Region savePathRegion(Path path) {
        if (path == null)
            return null;

        RectF rectf = new RectF();
        path.computeBounds(rectf, false);
        Region re = new Region();
        re.setPath(path, new Region((int) rectf.left, (int) rectf.top, (int) rectf.right, (int) rectf.bottom));
        return re;
    }




}

2017-06-15
移动边限制

package com.example.myapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Xfermode;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Project_name: MyApplication2
 * Date: 2017/3/2511:09
 * Email: xiaoxilong5201314@163.com.
 * Author: Aaron Empire
 * Description: TODO
 */


public class FunctionView extends View {


    public static final String TAG = "MultifunctionView";
    private Context context;
    private Bitmap mBitmap;
    private Canvas mCanvas, mpCanvas;
    private Path mPath;
    private Paint mBitmapPaint, mPaint;
    private float mX, mY;
    public static final float TOUCH_TOLERANCE = 4;
    private float startTranslateX;
    private float startTranslateY;
    private Paint mp;
    private float currentTranslateX;
    private float currentTranslateY;
    private float tempTranslateX;
    private float mMoveX;
    private float tempTranslateY;
    private float mMoveY;

    public static List<DrawPath> getSavePath() {
        return savePath;
    }

    public static void setSavePath(List<DrawPath> savePath) {
        FunctionView.savePath = savePath;
    }

    public static List<DrawPath> getDeletePath() {
        return deletePath;
    }

    public static void setDeletePath(List<DrawPath> deletePath) {
        FunctionView.deletePath = deletePath;
    }

    private static List<DrawPath> savePath;
    private static List<DrawPath> deletePath;
    private static List<DrawPath> tempPath;

    private DrawPath dp;
    private double screenWidth, screenHeight;
    private int currentColor = Color.RED;
    //    private int currentColor = 0x55ff0000;
    private float currentSize = 15;
    private int currentStyle = 1;
    private int[] paintColor;
    private PathMeasure pathMeasure;
    private Xfermode defaultMode;
    private int paintalpha;


    int mode = NONE;// 1为一个触摸点,2为两个触摸点
    static final int NONE = 0; //划线的指令
    static final int DRAG = 1;//拖拽指令
    static final int ZOOM = 2;//缩放指令
    static final int LOCKED = 3;//锁定Path,并绘制
    static final int CLEAN = 4;//  擦除模式
    int saveMode = mode;
    //缩放部分
    float oldDist = 1f;
    private float newDist;
    private float startX, startY;
    private float mScaleX = 4 / 3, mTranslateX, mTranslateY, mScaleY = 4 / 3;

    public FunctionView(Context context, int w, int h) {
        super(context);
        this.context = context;
        screenHeight = h;
        screenWidth = w;

        //六种颜色
        paintColor = new int[]{Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK, Color.GRAY, Color.CYAN, Color.TRANSPARENT};
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        initCanvas();
        savePath = new ArrayList<>();
        deletePath = new ArrayList<>();
        tempPath = new ArrayList<>();
        pathMeasure = new PathMeasure();


    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mode == NONE) {
            Rect src = new Rect((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
            RectF dest = new RectF(0, 0, (float) screenWidth, (float) screenHeight);
            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }
        if (mode == DRAG) {

            Rect src = new Rect((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
            RectF dest = new RectF(0, 0, (float) screenWidth, (float) screenHeight);
            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }
        if (mPath != null) {
            canvas.drawPath(mPath, mPaint);
        }
    }

    private void initCanvas() {
        setPaintStyle();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        mBitmap = Bitmap.createBitmap((int) screenWidth * 2, (int) screenHeight * 2, Bitmap.Config.ARGB_8888);
        mBitmap.eraseColor(Color.argb(255, 255, 255, 0));
        mCanvas = new Canvas(mBitmap);
        mCanvas.translate((int) (screenWidth / 2 + currentTranslateX), (int) (screenHeight / 2 + currentTranslateY));
        mTranslateX = (int) (screenWidth / 2 + currentTranslateX);
        mTranslateY = (int) (screenHeight / 2 + currentTranslateY);
    }

    private void setPaintStyle() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        defaultMode = mPaint.getXfermode();
        paintalpha = mPaint.getAlpha();
        if (currentStyle == 1) {
            mPaint.setStrokeWidth(currentSize);
            mPaint.setColor(currentColor);
        } else {
            //橡皮模式
//            mode = CLEAN;
            mPaint.setAlpha(0);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
            mPaint.setColor(Color.TRANSPARENT);
            mPaint.setStrokeWidth(50);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        startX = event.getX();
        startY = event.getY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:

                //画图模式
                if (mode == NONE) {
                    if (currentStyle == 1) {
                        //回复原状
                        mPaint.setColor(currentColor);
                        mPaint.setStrokeWidth(currentSize);
                    }
                    if (currentStyle == 2) {
//                        MoveView moveView = new MoveView(context);
//                        moveView.setDragState(true);
                    }

                    // 每次down下去重新new一个Path
                    mPath = new Path();
                    //每一次记录的路径对象是不一样的
                    dp = new DrawPath();
                    dp.setPath(mPath);
                    dp.setStrokeWidth(mPaint.getStrokeWidth());
                    dp.setPaintColor(mPaint.getColor());
                    touch_start(startX, startY);
                    invalidate();
                }


                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (event.getPointerCount() == 2) {
//                    mode = ZOOM;
//                    /**
//                     * 测量初始值
//                     */


                }
                if (event.getPointerCount() == 3) {
                    mode = DRAG;
                    startTranslateX = event.getX(0);
                    startTranslateY = event.getY(0);
                }


                break;
            case MotionEvent.ACTION_POINTER_UP:

                break;
            case MotionEvent.ACTION_MOVE:
                if (event.getPointerCount() == 2) {
                    newDist = getDistance(event);
                }
                if (mode == NONE) {
                    touch_move(startX, startY);
                    invalidate();
                    if (currentStyle == 2) {
                    }
                }


                if (mode == DRAG) {
                    tempTranslateX = currentTranslateX;
                    tempTranslateY = currentTranslateY;
                    currentTranslateX = currentTranslateX + (startTranslateX - event.getX(0));
                    currentTranslateY = currentTranslateY + (startTranslateY - event.getY(0));

                    //首先判断移动的位置x轴 y轴 在不在范围内
                    boolean translateXInRange = RangeInDefined(currentTranslateX, mTranslateX);
                    boolean translateYInRange = RangeInDefined(currentTranslateY, mTranslateY);

                    /**
                     * 移动X轴问题,Y轴在范围内
                     */
                    if ((!translateXInRange) && translateYInRange) {
                        if (currentTranslateX > mTranslateX) { //当向左移动,超出右边边边界时
                            currentTranslateX = mTranslateX;
                            mMoveX = mTranslateX - tempTranslateX;
//                            mCanvas.translate(mMoveX, (startTranslateY - event.getY(0)));
                        } else if (currentTranslateX < -mTranslateX) {
                            currentTranslateX = -mTranslateX;
                            mMoveX = -mTranslateX - tempTranslateX;

                        }
                        mCanvas.translate(mMoveX, (startTranslateY - event.getY(0)));

                    }
                    /**
                     * 移动Y轴问题,X轴在范围内
                     */
                    if ((!translateYInRange) && translateXInRange) {
                        if (currentTranslateY > mTranslateY) {
                            currentTranslateY = mTranslateY;
                            mMoveY = mTranslateY - tempTranslateY;
//                            mCanvas.translate((startTranslateX - event.getX(0)), mMoveY);
                        } else if (currentTranslateY < -mTranslateY) {
                            currentTranslateY = -mTranslateY;
                            mMoveY = -mTranslateY - tempTranslateY;
//                            mCanvas.translate((startTranslateX - event.getX(0)), mMoveY);
                        }

                        mCanvas.translate((startTranslateX - event.getX(0)), mMoveY);
                    }

                    /**
                     * X,Y轴都不在
                     */
                    if ((!translateXInRange) && (!translateYInRange)) {
                        /**
                         * 按四种情况,不然有点bug
                         *
                         */
                        if ((currentTranslateX > mTranslateX) && (currentTranslateY > mTranslateY)) {
                            currentTranslateX = mTranslateX;
                            mMoveX = mTranslateX - tempTranslateX;
                            currentTranslateY = mTranslateY;
                            mMoveY = mTranslateY - tempTranslateY;
//                                mCanvas.translate(mMoveX, mMoveY);
                        } else if ((currentTranslateX > mTranslateX) && (currentTranslateY < -mTranslateY)) {
                            currentTranslateX = mTranslateX;
                            mMoveX = mTranslateX - tempTranslateX;
                            currentTranslateY = -mTranslateY;
                            mMoveY = -mTranslateY - tempTranslateY;
//                                mCanvas.translate(mMoveX, mMoveY);
                        } else if ((currentTranslateX < -mTranslateX) && (currentTranslateY > mTranslateY)) {
                            currentTranslateX = -mTranslateX;
                            mMoveX = -mTranslateX - tempTranslateX;
                            currentTranslateY = mTranslateY;
                            mMoveY = mTranslateY - tempTranslateY;
//                                mCanvas.translate(mMoveX, mMoveY);
                        } else {
                            currentTranslateX = -mTranslateX;
                            mMoveX = -mTranslateX - tempTranslateX;
                            currentTranslateY = -mTranslateY;
                            mMoveY = -mTranslateY - tempTranslateY;
//                                mCanvas.translate(mMoveX, mMoveY);
                        }
                        mCanvas.translate(mMoveX, mMoveY);

//                        if (!translateXInRange) {
//                            if (currentTranslateX > mTranslateX) { //当向左移动,超出右边边边界时
//                                currentTranslateX = mTranslateX;
//                                mMoveX = mTranslateX - tempTranslateX;
//                                mCanvas.translate(mMoveX, 0);
//                            } else if (currentTranslateX < -mTranslateX) {
//                                currentTranslateX = -mTranslateX;
//                                mMoveX = -mTranslateX - tempTranslateX;
//                                mCanvas.translate(mMoveX, 0);
//                            }
//                        }
//                        if (!translateYInRange) {
//                            if (currentTranslateY > mTranslateY) {
//                                currentTranslateY = mTranslateY;
//                                mMoveY = mTranslateY - tempTranslateY;
//                                mCanvas.translate(0, mMoveY);
//                            } else if (currentTranslateY < -mTranslateY) {
//                                currentTranslateY = -mTranslateY;
//                                mMoveY = -mTranslateY - tempTranslateY;
//                                mCanvas.translate(0, mMoveY);
//                            }
//                        }
                    }
                    /**
                     *
                     * X轴Y轴都在
                     *
                     */
                    if (translateXInRange && translateYInRange) {
                        mCanvas.translate((startTranslateX - event.getX(0)), (startTranslateY - event.getY(0)));
                    }
                    invalidate();
                    startTranslateX = event.getX(0);
                    startTranslateY = event.getY(0);
                }

                break;
            case MotionEvent.ACTION_UP:
                if (mode == NONE) {
                    touch_up();
                    invalidate();
                    mode = NONE;
                }
                mode = NONE;


                break;
        }
        return true;
    }

    /**
     * 图片缩放,拖拽,部分方法
     */
    private float getDistance(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    /**
     * 划线部分操作
     */
    private void touch_start(float x, float y) {
        //初始化path点
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        //存起点
        PointF startPoint = new PointF();
        startPoint.set(x, y);
        dp.setStartPoint(startPoint);

        mCanvas.drawPath(mPath, mPaint);
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(mY - y);
        //两点间距离大于4 生成贝塞尔曲线
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            //贝塞尔曲线mX, mY为控制点  (x + mX) / 2, (y + mY) / 2 为终点
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;

            mCanvas.drawPath(mPath, mPaint);
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        PathMeasure pathMeasure = new PathMeasure(mPath, false);
        int length = (int) pathMeasure.getLength();
//        Log.i(TAG, "路径是点的长度: " + pathMeasure.getLength());

        if (length != 0) {
            //存尾点
            PointF startPoint = new PointF();
            startPoint.set(mX, mY);
            dp.setEndPoint(startPoint);
            //绘制整个平滑的线条
            //存Path 区域
            dp.setRegion(savePathRegion(mPath));
            dp.setXfermode(mPaint.getXfermode());
            dp.setPaintalpha(mPaint.getAlpha());
            mCanvas.drawPath(mPath, mPaint);
            savePath.add(dp);
            mPath = null;
            dp = null;

        } else {
        }

        Log.i("touch_up", "touch_up: " + savePath.size());
    }

    public void selectPaintSize(int which) {
        currentSize = which;
        setPaintStyle();
    }

    public void selectPainColor(int which) {
        mode = NONE;
        currentStyle = 1;
        currentColor = paintColor[which];
        setPaintStyle();
    }

    public void selectPainErase() {
        currentStyle = 2;
        setPaintStyle();
    }

    public void Revoked() {
        if (savePath != null && savePath.size() > 0) {
            DrawPath drawPath = savePath.get(savePath.size() - 1);
            deletePath.add(drawPath);
            savePath.remove(savePath.size() - 1);
            redrawOnBitmap();
        }
    }

    private void redrawOnBitmap() {
        initCanvas();
        Iterator<DrawPath> it = savePath.iterator();
        while (it.hasNext()) {
            DrawPath drawPath = it.next();
            mPaint.setStrokeWidth(drawPath.getStrokeWidth());
            mPaint.setColor(drawPath.getPaintColor());
            mPaint.setAlpha(drawPath.getPaintalpha());
            mPaint.setXfermode(drawPath.getXfermode());

            Log.i(TAG, "redrawOnBitmap: " + drawPath.getPaintalpha());

            mCanvas.drawPath(drawPath.getPath(), mPaint);
        }
        invalidate();
    }

    public void Redrawed() {
        if (deletePath.size() > 0) {
            DrawPath dp = deletePath.get(deletePath.size() - 1);
            savePath.add(dp);
            deletePath.remove(deletePath.size() - 1);

            mPaint.setStrokeWidth(dp.getStrokeWidth());
            mPaint.setColor(dp.getPaintColor());
            mPaint.setAlpha(dp.getPaintalpha());
            mPaint.setXfermode(dp.getXfermode());

            mCanvas.drawPath(dp.getPath(), mPaint);
            invalidate();
        }
    }

    public void StandardRedrawed() {
        invalidate();
    }


    /**
     * 点击变大
     */
    public void getBitImag(DrawPath drawPath, float scale, float centerX, float centerY, int position) {
        changePath(drawPath, scale, centerX, centerY, position);
    }

    public void changePath(DrawPath drawPath, float scale, float centrerX, float centerY, int position) {


        PathMeasure pathMeasure = new PathMeasure();
        pathMeasure.getLength();
        Path path = drawPath.getPath();

        float currentWidth = drawPath.getStrokeWidth();
        float scaleStrokeWidth = currentWidth * scale;

        Matrix matrix = new Matrix();
        matrix.setScale(scale, scale, (int) centrerX, (int) centerY);
        path.transform(matrix);

        drawPath.setStrokeWidth(scaleStrokeWidth);
        drawPath.setPath(path);

        savePath.set(position, drawPath);

        initCanvas();

        Iterator<DrawPath> it = savePath.iterator();
        while (it.hasNext()) {
            DrawPath drawPath1 = it.next();

            mPaint.setStrokeWidth(drawPath1.getStrokeWidth());
            mPaint.setColor(drawPath1.getPaintColor());
            mPaint.setAlpha(drawPath1.getPaintalpha());
            mPaint.setXfermode(drawPath1.getXfermode());

            mCanvas.drawPath(drawPath1.getPath(), mPaint);
        }

        invalidate();

    }


    public void cleanScreen() {
        Toast.makeText(context, "clean Screen !", Toast.LENGTH_SHORT).show();
        initCanvas();
        savePath.clear();
        deletePath.clear();
        invalidate();

    }


    public void savePaintContent() {

        Toast.makeText(context, "操作了!", Toast.LENGTH_SHORT).show();
        saveBitmap("hello", mBitmap);
    }

    /**
     * 保存图片
     *
     * @param bitName
     * @param mBitmap
     * @return
     */
    public static String saveBitmap(String bitName, Bitmap mBitmap) {


        File f = new File("/sdcard/" + bitName + ".png");

        try {
            f.createNewFile();
        } catch (IOException e) {
            System.out.println("在保存图片时出错:" + e.toString());
        }
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
        } catch (Exception e) {
            return "create_bitmap_error";
        }
        try {
            fOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "/sdcard/" + bitName + ".png";
    }

    // 存Path 区域对象Region
    public Region savePathRegion(Path path) {
        if (path == null)
            return null;

        RectF rectf = new RectF();
        path.computeBounds(rectf, false);
        Region re = new Region();
        re.setPath(path, new Region((int) rectf.left, (int) rectf.top, (int) rectf.right, (int) rectf.bottom));
        return re;
    }


    /**
     * new Bitmap 变换矩阵
     */
    private Bitmap scaleBitmap(Bitmap origin, float scale) {
        if (origin == null) {
            return null;
        }
        int height = origin.getHeight() > screenHeight * 2 ? (int) (screenHeight * 2) : origin.getHeight();
        int width = origin.getWidth() > screenWidth * 2 ? (int) (screenWidth * 2) : origin.getWidth();
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, true);
        if (!origin.isRecycled()) {
            origin.recycle();
        }
        return newBM;
    }


    public boolean RangeInDefined(int current, int min, int max) {
        return Math.max(min, current) == Math.min(current, max);
    }

    public boolean RangeInDefined(float current, float tanslate) {
        return Math.max(-tanslate, current) == Math.min(current, tanslate);
    }
}

遇到的坑,四边不同变大 ,结果变形

 if (event.getPointerCount() == 2) {
                    mode = ZOOM;
                    /**
                     * 测量初始值,记录初始两点
                     */
                    float startDis = getDistance(event);
                    startPointA = new PointF(event.getX(0), event.getY(0));
                    startPointB = new PointF(event.getX(1), event.getY(1));
//                    Toast.makeText(context, "点的值" + "startPointA:" + startPointA.x + ":" + startPointA.y + "startPointB:" + startPointB.x + ":" + startPointB.y, Toast.LENGTH_SHORT).show();

                }
  /**
                 * 测量缩放后的手势距离
                 */
                if (mode == ZOOM) {
                    float endDis = getDistance(event);
                    endPointA = new PointF(event.getX(0), event.getY(0));
                    endPointB = new PointF(event.getX(1), event.getY(1));

                    /**
                     * 得到点之后,把上下左右的四个方位移动的距离,计算出来,四个方位分管有两种局面,A上B下,或者B上A下
                     * 首先管控第一种A上B下情况
                     */

                    if (startPointA.x < startPointB.x && (startPointA.y < startPointB.y)) {
                        disLeft = endPointA.x - startPointA.x;
                        disTop = endPointA.y - startPointA.y;
                        disright = endPointB.x - startPointB.x;
                        disBottom = endPointB.y - startPointB.y;
                    } else {
                        disLeft = endPointA.x - startPointA.x;
                        disBottom = endPointA.y - startPointA.y;
                        disright = endPointB.x - startPointB.x;
                        disTop = endPointB.y - startPointB.y;
                    }


                    Toast.makeText(context, "四个值得问题:" + "disLeft:" + disLeft + ":" + "disTop:" + disTop + "disright:" + disright + "disBottom:" + disBottom, Toast.LENGTH_SHORT).show();
                    invalidate();
  /**
         * 放大缩小
         *   disLeft = endPointA.x-startPointA.x;
         *  disTop = endPointA.y-startPointA.y;
         *  disright = endPointB.x-startPointB.x;
         *  disBottom = endPointB.y-startPointB.y;
         *
         */
        if (mode == DRAG) {
            Rect src = new Rect((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
            RectF dest = new RectF(0, 0, (float) screenWidth, (float) screenHeight);
            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }

2017-06-16 更新

package com.example.myapplication;

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.PathMeasure;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Xfermode;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Project_name: MyApplication2
 * Date: 2017/3/2511:09
 * Email: xiaoxilong5201314@163.com.
 * Author: Aaron Empire
 * Description: TODO
 */


public class FunctionView extends View {


    public static final String TAG = "MultifunctionView";
    private Context context;
    private Bitmap mBitmap;
    private Canvas mCanvas, mpCanvas;
    private Path mPath;
    private Paint mBitmapPaint, mPaint;
    private float mX, mY;
    public static final float TOUCH_TOLERANCE = 4;
    private float startTranslateX;
    private float startTranslateY;
    private Paint mp;
    private float currentTranslateX;
    private float currentTranslateY;
    private float tempTranslateX;
    private float mMoveX;
    private float tempTranslateY;
    private float mMoveY;
    private PointF startPointA;
    private PointF startPointB;
    private PointF endPointA;
    private PointF endPointB;
    private float disLeft;
    private float disTop;
    private float disright;
    private float disBottom;
    private float startDis;
    private float endDis;
    private float scaleDis;
    private Rect src;
    private float currentScaleDis;
    private final RectF dest;
    private float scaleDisY;

    public static List<DrawPath> getSavePath() {
        return savePath;
    }

    public static void setSavePath(List<DrawPath> savePath) {
        FunctionView.savePath = savePath;
    }

    public static List<DrawPath> getDeletePath() {
        return deletePath;
    }

    public static void setDeletePath(List<DrawPath> deletePath) {
        FunctionView.deletePath = deletePath;
    }

    private static List<DrawPath> savePath;
    private static List<DrawPath> deletePath;
    private static List<DrawPath> tempPath;

    private DrawPath dp;
    private double screenWidth, screenHeight;
    private int currentColor = Color.RED;
    //    private int currentColor = 0x55ff0000;
    private float currentSize = 15;
    private int currentStyle = 1;
    private int[] paintColor;
    private PathMeasure pathMeasure;
    private Xfermode defaultMode;
    private int paintalpha;


    int mode = NONE;// 1为一个触摸点,2为两个触摸点
    static final int NONE = 0; //划线的指令
    static final int DRAG = 1;//拖拽指令
    static final int ZOOM = 2;//缩放指令
    static final int LOCKED = 3;//锁定Path,并绘制
    static final int CLEAN = 4;//  擦除模式
    int saveMode = mode;
    //缩放部分
    float oldDist = 1f;
    private float newDist;
    private float startX, startY;
    private float mScaleX = 4 / 3, mTranslateX, mTranslateY, mScaleY = 4 / 3;

    public FunctionView(Context context, int w, int h) {
        super(context);
        this.context = context;
        screenHeight = h;
        screenWidth = w;

        //六种颜色
        paintColor = new int[]{Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK, Color.GRAY, Color.CYAN, Color.TRANSPARENT};
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        initCanvas();
        savePath = new ArrayList<>();
        deletePath = new ArrayList<>();
        tempPath = new ArrayList<>();
        pathMeasure = new PathMeasure();

        src = new Rect();
        dest = new RectF(0, 0, (float) screenWidth, (float) screenHeight);
        src.set((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));

    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mode == NONE) {

//            src.set((int) ( mTranslateX + currentTranslateX+ scaleDis),  (int) (mTranslateY + currentTranslateY + scaleDisY), (int) (mTranslateX * 3 + currentTranslateX - scaleDis), (int) (mTranslateY * 3 + currentTranslateY - scaleDisY));

//            src.set((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }
        /**
         * 放大缩小
         *   disLeft = endPointA.x-startPointA.x;
         *  disTop = endPointA.y-startPointA.y;
         *  disright = endPointB.x-startPointB.x;
         *  disBottom = endPointB.y-startPointB.y;
         *
         */
        if (mode == DRAG) {
//            src.set((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
            src.set((int) (mTranslateX + currentTranslateX + scaleDis), (int) (mTranslateY + currentTranslateY + scaleDisY), (int) (mTranslateX * 3 + currentTranslateX - scaleDis), (int) (mTranslateY * 3 + currentTranslateY - scaleDisY));

            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);
        }

        if (mode == ZOOM) {
            /**
             *
             * 判断放大边界条件
             *1.增加屏幕长,宽不一致问题导致的变换问题变行,增加参数scaleDisY
             */

            if (scaleDis > 0) {
                if (((mTranslateX * 2 - 2 * scaleDis) > 10) && ((mTranslateY * 2 - 2 * scaleDisY) > 10)) {

                    scaleDisY = scaleDis / mTranslateX * mTranslateY;

                    src.set((int) (mTranslateX + currentTranslateX + scaleDis), (int) (mTranslateY + currentTranslateY + scaleDisY), (int) (mTranslateX * 3 + currentTranslateX - scaleDis), (int) (mTranslateY * 3 + currentTranslateY - scaleDisY));
                } else if ((mTranslateX * 2 - 2 * scaleDis) <= 10 && ((mTranslateY * 2 - 2 * scaleDis) > 10)) {

                    if (mTranslateX < mTranslateY) {

                    } else {
                        scaleDis = mTranslateY - 5;
                    }
                    scaleDisY = scaleDis / mTranslateX * mTranslateY;
                    /**
                     * 参数有点问题,发生了变形
                     */
                    src.set((int) (mTranslateX + currentTranslateX + scaleDis), (int) (mTranslateY + currentTranslateY + scaleDisY), (int) (mTranslateX * 3 + currentTranslateX - scaleDis), (int) (mTranslateY * 3 + currentTranslateY - scaleDisY));
//                    src.set((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
                }
//                mCanvas.translate((int) (scaleDis), (int) ( scaleDisY) );
//                mCanvas.scale(scaleDis,scaleDisY);
//                mCanvas.translate((int) (scaleDis-((2*scaleDis)/(mTranslateX-scaleDis)*mTranslateX)), (int) ( scaleDisY) );
            } else {
                /**
                 * scaleDis<=0时,还在限制区域2倍显示区域时,做的操作!,少于两倍时,做限制操作!
                 */
                if ((mTranslateX + currentTranslateX + scaleDis > 0) && (mTranslateY + currentTranslateY + scaleDisY) > 0 && (-mTranslateX + currentTranslateX - scaleDis) < 0 && (-mTranslateY + currentTranslateY - scaleDisY) < 0) {

                    scaleDisY = scaleDis / mTranslateX * mTranslateY;
                    src.set((int) (mTranslateX + currentTranslateX + scaleDis), (int) (mTranslateY + currentTranslateY + scaleDisY), (int) (mTranslateX * 3 + currentTranslateX - scaleDis), (int) (mTranslateY * 3 + currentTranslateY - scaleDisY));
                } else {
                    scaleDisY = scaleDis / mTranslateX * mTranslateY;
                    /**
                     * 少于二倍,看是哪个边先超出了限制,没处理!
                     *
                     */
                    float tempX = Math.min(mTranslateX + currentTranslateX + scaleDis, mTranslateY + currentTranslateY + scaleDisY);
                    float tempY = Math.max(-3 * mTranslateX + currentTranslateX + scaleDis   , mTranslateY + currentTranslateY + scaleDisY);

                    src.set((int) (mTranslateX + currentTranslateX + scaleDis), (int) (mTranslateY + currentTranslateY + scaleDisY), (int) (mTranslateX * 3 + currentTranslateX - scaleDis), (int) (mTranslateY * 3 + currentTranslateY - scaleDisY));

//                    src.set((int) (mTranslateX + currentTranslateX), (int) (mTranslateY + currentTranslateY), (int) (mTranslateX * 3 + currentTranslateX), (int) (mTranslateY * 3 + currentTranslateY));
                }
            }

            canvas.drawBitmap(mBitmap, src, dest, mBitmapPaint);

//            mCanvas.translate((int) (screenWidth / 2 + currentTranslateX+scaleDis), (int) (screenHeight / 2 + currentTranslateY+ scaleDisY) );

        }
        if (mPath != null) {
            canvas.drawPath(mPath, mPaint);
        }
    }

    private void initCanvas() {
        setPaintStyle();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        mBitmap = Bitmap.createBitmap((int) screenWidth * 2, (int) screenHeight * 2, Bitmap.Config.ARGB_8888);
        mBitmap.eraseColor(Color.argb(255, 255, 255, 0));
        mCanvas = new Canvas(mBitmap);
        mCanvas.translate((int) (screenWidth / 2 + currentTranslateX), (int) (screenHeight / 2 + currentTranslateY));
        mTranslateX = (int) (screenWidth / 2 + currentTranslateX);
        mTranslateY = (int) (screenHeight / 2 + currentTranslateY);
    }

    private void setPaintStyle() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        defaultMode = mPaint.getXfermode();
        paintalpha = mPaint.getAlpha();
        if (currentStyle == 1) {
            mPaint.setStrokeWidth(currentSize);
            mPaint.setColor(currentColor);
        } else {
            //橡皮模式
//            mode = CLEAN;
            mPaint.setAlpha(0);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
            mPaint.setColor(Color.TRANSPARENT);
            mPaint.setStrokeWidth(50);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        startX = event.getX();
        startY = event.getY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:

                //画图模式
                if (mode == NONE) {
                    if (currentStyle == 1) {
                        //回复原状
                        mPaint.setColor(currentColor);
                        mPaint.setStrokeWidth(currentSize);
                    }
                    if (currentStyle == 2) {
//                        MoveView moveView = new MoveView(context);
//                        moveView.setDragState(true);
                    }

                    // 每次down下去重新new一个Path
                    mPath = new Path();
                    //每一次记录的路径对象是不一样的
                    dp = new DrawPath();
                    dp.setPath(mPath);
                    dp.setStrokeWidth(mPaint.getStrokeWidth());
                    dp.setPaintColor(mPaint.getColor());
                    touch_start(startX, startY);
                    invalidate();
                }


                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (event.getPointerCount() == 2) {
                    mode = ZOOM;
                    /**
                     * 测量初始值,记录初始两点
                     */
                    startDis = getDistance(event);
                    startPointA = new PointF(event.getX(0), event.getY(0));
                    startPointB = new PointF(event.getX(1), event.getY(1));
//                    Toast.makeText(context, "点的值" + "startPointA:" + startPointA.x + ":" + startPointA.y + "startPointB:" + startPointB.x + ":" + startPointB.y, Toast.LENGTH_SHORT).show();

                }
                if (event.getPointerCount() == 3) {
                    mode = DRAG;
                    startTranslateX = event.getX(0);
                    startTranslateY = event.getY(0);
                }


                break;
            case MotionEvent.ACTION_POINTER_UP:


                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == NONE) {
                    touch_move(startX, startY);
                    invalidate();
                    if (currentStyle == 2) {
                    }
                }
                if (event.getPointerCount() == 2) {
                    /**
                     * 测量缩放后的手势距离
                     */
                    if (mode == ZOOM) {
                        endDis = getDistance(event);

                        /**
                         *
                         * 计算手势前后的距离差
                         *
                         */
                        scaleDis = (endDis - startDis) / 2 + currentScaleDis;
                        endPointA = new PointF(event.getX(0), event.getY(0));
                        endPointB = new PointF(event.getX(1), event.getY(1));
                        invalidate();

                    }
                }
                if (mode == DRAG) {
                    tempTranslateX = currentTranslateX;
                    tempTranslateY = currentTranslateY;
                    currentTranslateX = currentTranslateX + (startTranslateX - event.getX(0));
                    currentTranslateY = currentTranslateY + (startTranslateY - event.getY(0));
                    //首先判断移动的位置x轴 y轴 在不在范围内
                    boolean translateXInRange = RangeInDefined(currentTranslateX, mTranslateX);
                    boolean translateYInRange = RangeInDefined(currentTranslateY, mTranslateY);
                    /**
                     * 移动X轴问题,Y轴在范围内
                     */
                    if ((!translateXInRange) && translateYInRange) {
                        if (currentTranslateX > mTranslateX) { //当向左移动,超出右边边边界时
                            currentTranslateX = mTranslateX;
                            mMoveX = mTranslateX - tempTranslateX;
//                            mCanvas.translate(mMoveX, (startTranslateY - event.getY(0)));
                        } else if (currentTranslateX < -mTranslateX) {
                            currentTranslateX = -mTranslateX;
                            mMoveX = -mTranslateX - tempTranslateX;

                        }
                        mCanvas.translate(mMoveX, (startTranslateY - event.getY(0)));
                    }
                    /**
                     * 移动Y轴问题,X轴在范围内
                     */
                    if ((!translateYInRange) && translateXInRange) {
                        if (currentTranslateY > mTranslateY) {
                            currentTranslateY = mTranslateY;
                            mMoveY = mTranslateY - tempTranslateY;
                        } else if (currentTranslateY < -mTranslateY) {
                            currentTranslateY = -mTranslateY;
                            mMoveY = -mTranslateY - tempTranslateY;
                        }
                        mCanvas.translate((startTranslateX - event.getX(0)), mMoveY);
                    }
                    /**
                     * X,Y轴都不在
                     */
                    if ((!translateXInRange) && (!translateYInRange)) {
                        /**
                         * 按四种情况,不然有点bug
                         *
                         */
                        if ((currentTranslateX > mTranslateX) && (currentTranslateY > mTranslateY)) {
                            currentTranslateX = mTranslateX;
                            mMoveX = mTranslateX - tempTranslateX;
                            currentTranslateY = mTranslateY;
                            mMoveY = mTranslateY - tempTranslateY;
                        } else if ((currentTranslateX > mTranslateX) && (currentTranslateY < -mTranslateY)) {
                            currentTranslateX = mTranslateX;
                            mMoveX = mTranslateX - tempTranslateX;
                            currentTranslateY = -mTranslateY;
                            mMoveY = -mTranslateY - tempTranslateY;
                        } else if ((currentTranslateX < -mTranslateX) && (currentTranslateY > mTranslateY)) {
                            currentTranslateX = -mTranslateX;
                            mMoveX = -mTranslateX - tempTranslateX;
                            currentTranslateY = mTranslateY;
                            mMoveY = mTranslateY - tempTranslateY;
                        } else {
                            currentTranslateX = -mTranslateX;
                            mMoveX = -mTranslateX - tempTranslateX;
                            currentTranslateY = -mTranslateY;
                            mMoveY = -mTranslateY - tempTranslateY;
                        }
                        mCanvas.translate(mMoveX, mMoveY);
                    }
                    /**
                     *
                     * X轴Y轴都在
                     *
                     */
                    if (translateXInRange && translateYInRange) {
                        mCanvas.translate((startTranslateX - event.getX(0)), (startTranslateY - event.getY(0)));
                    }
                    invalidate();
                    startTranslateX = event.getX(0);
                    startTranslateY = event.getY(0);
                }

                break;
            case MotionEvent.ACTION_UP:
                if (mode == NONE) {
                    touch_up();
                    invalidate();
                    mode = NONE;
                }
                if (mode == ZOOM) {
                    /**
                     * 累积每次放大后的倍数参数currenScaleDis
                     *
                     */
                    currentScaleDis = scaleDis;

                }


                mode = NONE;


                break;
        }
        return true;
    }

    /**
     * 图片缩放,拖拽,部分方法
     */
    private float getDistance(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    /**
     * 划线部分操作
     */
    private void touch_start(float x, float y) {
        //初始化path点
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        //存起点
        PointF startPoint = new PointF();
        startPoint.set(x, y);
        dp.setStartPoint(startPoint);

        mCanvas.drawPath(mPath, mPaint);
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(mY - y);
        //两点间距离大于4 生成贝塞尔曲线
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            //贝塞尔曲线mX, mY为控制点  (x + mX) / 2, (y + mY) / 2 为终点
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;

            mCanvas.drawPath(mPath, mPaint);
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        PathMeasure pathMeasure = new PathMeasure(mPath, false);
        int length = (int) pathMeasure.getLength();
//        Log.i(TAG, "路径是点的长度: " + pathMeasure.getLength());

        if (length != 0) {
            //存尾点
            PointF startPoint = new PointF();
            startPoint.set(mX, mY);
            dp.setEndPoint(startPoint);
            //绘制整个平滑的线条
            //存Path 区域
            dp.setRegion(savePathRegion(mPath));
            dp.setXfermode(mPaint.getXfermode());
            dp.setPaintalpha(mPaint.getAlpha());
            mCanvas.drawPath(mPath, mPaint);
            savePath.add(dp);
            mPath = null;
            dp = null;

        } else {
        }

        Log.i("touch_up", "touch_up: " + savePath.size());
    }

    public void selectPaintSize(int which) {
        currentSize = which;
        setPaintStyle();
    }

    public void selectPainColor(int which) {
        mode = NONE;
        currentStyle = 1;
        currentColor = paintColor[which];
        setPaintStyle();
    }

    public void selectPainErase() {
        currentStyle = 2;
        setPaintStyle();
    }

    public void Revoked() {
        if (savePath != null && savePath.size() > 0) {
            DrawPath drawPath = savePath.get(savePath.size() - 1);
            deletePath.add(drawPath);
            savePath.remove(savePath.size() - 1);
            redrawOnBitmap();
        }
    }

    private void redrawOnBitmap() {
        initCanvas();
        Iterator<DrawPath> it = savePath.iterator();
        while (it.hasNext()) {
            DrawPath drawPath = it.next();
            mPaint.setStrokeWidth(drawPath.getStrokeWidth());
            mPaint.setColor(drawPath.getPaintColor());
            mPaint.setAlpha(drawPath.getPaintalpha());
            mPaint.setXfermode(drawPath.getXfermode());

            Log.i(TAG, "redrawOnBitmap: " + drawPath.getPaintalpha());

            mCanvas.drawPath(drawPath.getPath(), mPaint);
        }
        invalidate();
    }

    public void Redrawed() {
        if (deletePath.size() > 0) {
            DrawPath dp = deletePath.get(deletePath.size() - 1);
            savePath.add(dp);
            deletePath.remove(deletePath.size() - 1);

            mPaint.setStrokeWidth(dp.getStrokeWidth());
            mPaint.setColor(dp.getPaintColor());
            mPaint.setAlpha(dp.getPaintalpha());
            mPaint.setXfermode(dp.getXfermode());

            mCanvas.drawPath(dp.getPath(), mPaint);
            invalidate();
        }
    }

    public void StandardRedrawed() {
        invalidate();
    }


    public void cleanScreen() {
        Toast.makeText(context, "clean Screen !", Toast.LENGTH_SHORT).show();
        initCanvas();
        savePath.clear();
        deletePath.clear();
        invalidate();

    }


    public void savePaintContent() {

        Toast.makeText(context, "操作了!", Toast.LENGTH_SHORT).show();
        saveBitmap("hello", mBitmap);
    }

    /**
     * 保存图片
     *
     * @param bitName
     * @param mBitmap
     * @return
     */
    public static String saveBitmap(String bitName, Bitmap mBitmap) {


        File f = new File("/sdcard/" + bitName + ".png");

        try {
            f.createNewFile();
        } catch (IOException e) {
            System.out.println("在保存图片时出错:" + e.toString());
        }
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
        } catch (Exception e) {
            return "create_bitmap_error";
        }
        try {
            fOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "/sdcard/" + bitName + ".png";
    }

    // 存Path 区域对象Region
    public Region savePathRegion(Path path) {
        if (path == null)
            return null;

        RectF rectf = new RectF();
        path.computeBounds(rectf, false);
        Region re = new Region();
        re.setPath(path, new Region((int) rectf.left, (int) rectf.top, (int) rectf.right, (int) rectf.bottom));
        return re;
    }


    public boolean RangeInDefined(int current, int min, int max) {
        return Math.max(min, current) == Math.min(current, max);
    }

    public boolean RangeInDefined(float current, float tanslate) {
        return Math.max(-tanslate, current) == Math.min(current, tanslate);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值