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