编写之前需要了解的知识点
自定义 view
画笔 paint
路径 path
画布 canvas
别写这个的时候遇见好大的一个坑,就是使用canvas时,使用paint画笔具有透明度,每次都是调试不出来这个带透明的画笔,其实很简单的问题,让我疑惑了一天。
以上就是我在编写的时候遇见的问题
先上图,看一下带透明度的线
本节主要讲解最基础的部分
private static final int INIT_PEN_WIDTH = 80;
/**
* 画笔的模式
*/
public static final int MODE_PEN = 0;
public static final int MODE_ERASER = 1;
private float mX, mY;
private float TOUCH_TOLERANCE = 4;
private int mMode;
private Paint mPenPaint;//画画的画笔
private Paint mEraserPaint;//用于橡皮擦的画笔
private int mPenWidth;//用于保存当前的画笔宽度
private int mPenColor;//用于保存当前画笔的颜色
private Paint.Style mPenStyle; //当前画笔的样式
private int mEraserWidth = 50;//用于保存当前橡皮擦的宽度
private Canvas mPenCanvas;//用于画画的画板
private Bitmap mPenBitmap;//一个空白的图片,通过画板控制 mPenCanvas;
以上是画板的参数
初始化橡皮擦的画笔属性
mEraserPaint = new Paint();
mEraserPaint.setStrokeWidth(mEraserWidth);
mEraserPaint.setAlpha(0);
//这个属性是设置paint为橡皮擦重中之重
//这是重点
mEraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
//上面这句代码是橡皮擦设置的重点(重要的事是不是一定要说三遍)
mEraserPaint.setAntiAlias(true);
mEraserPaint.setDither(true);
mEraserPaint.setStyle(Paint.Style.STROKE);
mEraserPaint.setStrokeJoin(Paint.Join.ROUND);
mEraserPaint.setStrokeWidth(mEraserWidth);这里橡皮擦的画笔初始化,所要求的知识点比较全面,如果把这个搞明白了,画笔Paint的基本使用你就没有问题了。
下面是对画画的画笔进行初始化
mPenPaint = new Paint();
mPenPaint.setAntiAlias(true);
mPenPaint.setStrokeWidth(mPenWidth);
mPenPaint.setStyle(mPenStyle);
mPenPaint.setColor(mPenColor);
mPenPaint.setStrokeCap(Paint.Cap.ROUND);
mPenPaint.setStrokeJoin(Paint.Join.ROUND);
下面呢对画布进行初始化操作
//创建一个画布背景
mPenBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
//用于操作的画布
mPenCanvas = new Canvas(mPenBitmap);
下面的具体操作就是在OnTouchListener的滑动事件对手势进行操作
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown(event);
break;
case MotionEvent.ACTION_UP:
touchUp(event);
break;
case MotionEvent.ACTION_MOVE:
touchMove(event);
break;
}
return true;
}
然后就是touchDown方法内的内容,里面主要创建一个每次操作的启示初始化工作;
private voidtouchDown(MotionEvent event) {
floatx = event.getX();floaty = event.getY();mX= x;mY= y;DrawParams drawParams = newDrawParams();if(mMode== MODE_PEN) {
drawParams.paint= newPaint(mPenPaint);} else if(mMode== MODE_ERASER) {
drawParams.paint= newPaint(mEraserPaint);}
drawParams.path= newPath();drawParams.path.moveTo(x,y);//mPath.moveTo(x, y);mDrawList.add(drawParams);invalidate();}
下面的就是touchMove方法是比较重点的地方
private voidtouchMove(MotionEvent event) {
floatx = event.getX();floaty = event.getY();floatdx = Math.abs(x - mX);floatdy = Math.abs(y - mY);if(dx >= TOUCH_TOLERANCE|| dy >= TOUCH_TOLERANCE) {mDrawList.get(mDrawList.size() - 1).path.quadTo(mX,mY,(x + mX) / 2,(y + mY) / 2);invalidate();}
mX= x;mY= y;}
下面是onDraw的具体方法
@Overrideprotected voidonDraw(Canvas canvas) {
initDraw();/*** 用于解决 使用透明色时,划线颜色一直加深的问题,该方法就是每次操作的时候都会把画板用橡皮擦清空内容* 然后在让保存的每次操作进行对画板的设置;*/mPenCanvas.drawBitmap(mPenBitmap,0,0,mEraserPaint);if(mDrawList.size() > 0)
for(inti = 0;i < mDrawList.size();i++) {
DrawParams drawParams = mDrawList.get(i);mPenCanvas.drawPath(drawParams.path,drawParams.paint);}
canvas.drawBitmap(mPenBitmap,0,0, null);super.onDraw(canvas);}
总感觉代码太过简单,所以没有描述过多。这都是基础。就是实现画笔带有透明度的时候总是 Path路径不带透明度,让我郁闷一天,后来才想到,只要加一行代码一切都解决。
上网查了好多资料都没有,在阳台抽烟忽悠一下想到的,真就是灵光一闪,答案就出来了。
下面我就把全部源码贡献,希望对你有帮助,我还会继续的扩展,我们老大要让我做一个带图片缩放,对图片进行绘画的功能软件,等完毕后,把工程上传让大家分享。
/**
* Created by mrqiu on 2017/4/3.
*/
public class DrawView extends View implements View.OnTouchListener {
private static final int INIT_PEN_WIDTH = 80;
/**
* 画笔的模式
*/
public static final int MODE_PEN = 0;
public static final int MODE_ERASER = 1;
private ArrayListmDrawList;//用于存储每次的操作
private float mX, mY;
private float TOUCH_TOLERANCE = 4;
private int mMode;
private Paint mPenPaint;//画画的画笔
private Paint mEraserPaint;//用于橡皮擦的画笔
private int mPenWidth;//用于保存当前的画笔宽度
private int mPenColor;//用于保存当前画笔的颜色
private Paint.Style mPenStyle; //当前画笔的样式
private int mEraserWidth = 50;//用于保存当前橡皮擦的宽度
private Canvas mPenCanvas;//用于画画的画板
private Bitmap mPenBitmap;//一个空白的图片,通过画板控制 mPenCanvas;
public DrawView(Context context) {
super(context);
init(context, null, 0);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
mDrawList = new ArrayList<>();
mPenColor = Color.BLUE;
mPenStyle = Paint.Style.STROKE;
mPenWidth = INIT_PEN_WIDTH;
mPenPaint = new Paint();
mPenPaint.setAntiAlias(true);
mPenPaint.setStrokeWidth(mPenWidth);
mPenPaint.setStyle(mPenStyle);
mPenPaint.setColor(mPenColor);
mPenPaint.setStrokeCap(Paint.Cap.ROUND);
mPenPaint.setStrokeJoin(Paint.Join.ROUND);
mEraserPaint = new Paint();
mEraserPaint.setStrokeWidth(mEraserWidth);
mEraserPaint.setAlpha(0);
//这个属性是设置paint为橡皮擦重中之重
//这是重点
mEraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
//上面这句代码是橡皮擦设置的重点(重要的事是不是一定要说三遍)
mEraserPaint.setAntiAlias(true);
mEraserPaint.setDither(true);
mEraserPaint.setStyle(Paint.Style.STROKE);
mEraserPaint.setStrokeJoin(Paint.Join.ROUND);
mEraserPaint.setStrokeWidth(mEraserWidth);
//创建一个画布背景
mPenBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
//用于操作的画布
mPenCanvas = new Canvas(mPenBitmap);
setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown(event);
break;
case MotionEvent.ACTION_UP:
touchUp(event);
break;
case MotionEvent.ACTION_MOVE:
touchMove(event);
break;
}
return true;
}
private void touchMove(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
//mPath.reset();
//mPath.moveTo(mX,mY);
//mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mDrawList.get(mDrawList.size() - 1).path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
Log.i("touchMove", "touchMove: " + mX + ",mY=" + mY + "," + mDrawList.size());
invalidate();
}
mX = x;
mY = y;
}
private void touchUp(MotionEvent event) {
}
private void touchDown(MotionEvent event) {
float x = event.getX();
float y = event.getY();
mX = x;
mY = y;
DrawParams drawParams = new DrawParams();
if (mMode == MODE_PEN) {
drawParams.paint = new Paint(mPenPaint);
} else if (mMode == MODE_ERASER) {
drawParams.paint = new Paint(mEraserPaint);
}
drawParams.path = new Path();
drawParams.path.moveTo(x, y);
//mPath.moveTo(x, y);
mDrawList.add(drawParams);
invalidate();
}
public void setMode(int mode) {
mMode = mode;
}
public static class DrawParams {
Path path;
Paint paint;
}
private void initDraw() {
mPenCanvas.drawColor(Color.argb(0, 0, 0, 0));
}
@Override
protected void onDraw(Canvas canvas) {
initDraw();
/**
* 用于解决 使用透明色时,划线颜色一直加深的问题,该方法就是每次操作的时候都会把画板用橡皮擦清空内容
* 然后在让保存的每次操作进行对画板的设置;
*/
mPenCanvas.drawBitmap(mPenBitmap, 0, 0, mEraserPaint);
if (mDrawList.size() > 0)
for (int i = 0; i < mDrawList.size(); i++) {
DrawParams drawParams = mDrawList.get(i);
mPenCanvas.drawPath(drawParams.path, drawParams.paint);
}
canvas.drawBitmap(mPenBitmap, 0, 0, null);
super.onDraw(canvas);
}
public void setPenColor(int penColor) {
this.mPenColor = penColor;
mPenPaint.setColor(penColor);
}
}