Android一般实现一个画板功能,都能想到去坚定ontouch方法,然后通过这个方法返回的按下,移动,抬起,的回调监听,不断的更改在屏幕上的X,Y值,然后通过paint在canvas上不断的绘制,然后剩下的就是调整抗锯齿,画笔的平滑度等操作。
没错,大概思路也是如此,所以这篇文章也只是针对当前通用的画板进行细节处理和描述。首先看一下ontouch方法吧,这个方法主要的也是分发的功能。
@Override
public boolean onTouchEvent(MotionEvent event) {
float x=event.getX();
float y=event.getY();
currentX=x;
currentY=y;
isTouchUp=false;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
oldx=x;oldy=y;
down(x,y);
//配合撤销,没有移动也要可以撤销 (仅仅只是点击操作)
getParent().requestDisallowInterceptTouchEvent(true);
move(x,y);
break;
case MotionEvent.ACTION_MOVE:
getParent().requestDisallowInterceptTouchEvent(true);
move(x,y);
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
return false;
case MotionEvent.ACTION_UP:
if (handwriting.hasDraw()){
padUndoStack.push(handwriting);
if (mCallBack!=null)mCallBack.onHasDraw();
}
up(event.getX(),event.getY());
isTouchUp = true;
invalidate();
break;
}
return true;
}
private void down(float x,float y){
commCanvas.setBitmap(drawBitmap);
createNewPen();
if (handwriting!=null){
handwriting.touchDown(x,y);
}
if (mCallBack!=null){
mCallBack.onTouchDown();
}
}
private void move(float x,float y){
handwriting.touchMove(x,y);
if (paintType== PaintConstants.PEN_TYPE.ERASER){
handwriting.draw(commCanvas,false);
}
}
private void up(float x,float y){
if (handwriting==null){
return;
}
handwriting.touchUp(x,y);
handwriting.draw(commCanvas,true);
final float dx=Math.abs(oldx-x);
final float dy=Math.abs(oldy-y);
if (dx==0&&dy==0){
handwriting.touchUp(x+1,y);
handwriting.draw(commCanvas,true);
}
}
下面要先介绍一下PorterDuff.Mode。下面的操作要灵活使用到这个东西,用来实现橡皮擦功能,和画笔功能,要不然在画板中就会各种凌乱了。
再来看看画笔的这一部分代码:
@Override
public void draw(Canvas canvas,boolean isUp) {
if (canvas != null) {
mFirstCurrentPosition.currentX = mCurrentX;
mFirstCurrentPosition.currentY = mCurrentY;
int color = mPenPaint.getColor();
if (isUp){
mPenPaint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC));
if (mPenPaint.getColor()== Color.parseColor("#ffffff")||mPenPaint.getColor()== Color.parseColor("#303030")){
mPenPaint.setAlpha(204);
}else {
mPenPaint.setAlpha(153);
}
}else {
mPenPaint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
if (mPenPaint.getColor()== Color.parseColor("#ffffff")||mPenPaint.getColor()== Color.parseColor("#303030")){
mPenPaint.setAlpha(204);
}else {
mPenPaint.setAlpha(153);
}
}
currentShape.draw(canvas, mPenPaint);
}
}
protected void initPaint(int penSize, int penColor, Style style) {
mPenPaint = new Paint();
mPenPaint.setStrokeWidth(penSize);
mPenPaint.setColor(penColor);
this.penSize = penSize;
this.style = style;
mPenPaint.setDither(true);
mPenPaint.setAntiAlias(true);
mPenPaint.setStyle(style);
mPenPaint.setStrokeJoin(Paint.Join.ROUND);
mPenPaint.setStrokeCap(Paint.Cap.ROUND);
mPenPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
}
这里给画笔的颜色设置的一个透明度,这个主要是最大化的还原在移动过程中和抬起后,所绘制的颜色色差降到最小,要不然在移动画笔过程中,颜色就会特别的深,而且颜色色值都有所改变,现在加个透明度,效果就是感觉画笔像打湿了一样。剩下的paint的一些属性设置,比如抗锯齿之类的,只是让这个画笔更加的润滑。
再来看看橡皮擦的方法的,橡皮擦就比较简单了:
private void setUp() {
// color并不中还要,混色的模式决定了eraser
mEraserPaint.setColor(Color.BLACK);
mEraserPaint.setDither(true);
mEraserPaint.setAntiAlias(true);
mEraserPaint.setStyle(Paint.Style.STROKE);
mEraserPaint.setStrokeJoin(Paint.Join.ROUND);
mEraserPaint.setStrokeCap(Paint.Cap.ROUND);
mEraserPaint
.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
@Override
public void draw(Canvas canvas,boolean isUp) {
if (null != canvas) {
canvas.drawPath(mPath, mEraserPaint);
}
}
然后各种撤回操作,只是将回执的xy记录在一个list中,撤回时候去取这个记录:
/**
* undo
*/
public void undo() {
if (canUndo() && null != mDrawing) {
CommHandwriting removedTool = mUndoStack
.get(mUndoStack.size() - 1);
mRedoStack.add(removedTool);
mUndoStack.remove(mUndoStack.size() - 1);
renewDraw();
}
}
/**
* redo
*/
public void redo() {
if (canRedo() && null != mDrawing) {
CommHandwriting removedTool = mRedoStack
.get(mRedoStack.size() - 1);
mUndoStack.add(removedTool);
mRedoStack.remove(mRedoStack.size() - 1);
renewDraw();
}
}
private void renewDraw(){
if (null != originalBitmap&&!originalBitmap.isRecycled()) {
// Set the temporary fore bitmap to canvas.
// 当载入文件时保存了一份,现在要重新绘制出来
mDrawing.setTempForeBitmap(mDrawing.originalBitmap);
} else {
// 如果背景不存在,则重新创建一份背景
mDrawing.createCanvasBitmap(mDrawing.drawingBroadWidth,
mDrawing.drawingBroadHeight);
}
Canvas canvas = mDrawing.commCanvas;
// First draw the removed tools from undo stack.
for (CommHandwriting paintTool : mOldActionStack) {
paintTool.draw(canvas,true);
}
for (CommHandwriting paintTool : mUndoStack) {
paintTool.draw(canvas,true);
}
mDrawing.invalidate();
}
剩下的clearAll的操作,其实也只是使用到了paint的setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));这个方法,也就是上面粘贴出来截图的属性。
那么这样一来一个画板就这么实现了。剩下的只是根据页面进行调用就行了,当然也提供了demo以供下载查看:
https://download.csdn.net/download/greatdaocaoren/12568959
有兴趣可以看看下面服务号和订阅号: