需求功能详解
单纯的编辑图片的功能,能够在界面上进行图形的绘制,线条的涂鸦,和画马赛克的绘制,并且有撤销的功能。话不多说,直接看一下效果吧:

主要实现思路
实现一个自定义View,重写onDraw(),集成这些编辑功能。
-
功能集成
该编辑功能有涂鸦,画图形,画文字,和马赛克的功能,这里只对除了文字的内容进行介绍,若想进一步获得文字功能,可在代码库中pull代码,并自己打开该功能:
public enum MODE {
NONE, GRAPH_MODE, DOODLE_MODE, MOSAIC_MODE, DRAG, ZOOM
}
- 涂鸦
先说最简单的涂鸦吧,涂鸦功能实际就是在界面上画线,路径跟着手指移动就完事了。由于有撤销的功能,所以需要把Path都保存起来,在按下时new Path()
,并且moveTo
按下的位置,在手指移动过程中,将这条pathlineTo
相对应的位置,手指抬起时结束,那么一条路径不就画完了吗!
/**
* 涂鸦的路径
*/
private ArrayList<DrawPathBean> mDoodlePath = new ArrayList<>();
涂鸦功能的实例:
/**
* 记录画笔和画图的路径,主要用来撤销画图的操作
*/
class DrawPathBean {
public Path path;
public Paint paint;
public MODE mode;
DrawPathBean(Path path, Paint paint, MODE mode) {
this.paint = paint;
this.path = path;
this.mode = mode;
}
}
为了之后的撤销操作,需要将路径记录下来。
在Action_Down
中新建画笔和路径,并添加到List
中,
// 设置对应mode的画笔
setModePaint(mMode);
mTempPath = new Path();
mStartX = mMoveX;
mStartY = mMoveY;
mTempPath.moveTo(mStartX, mStartY);
// 把path加到队列中
DrawPathBean pathBean = new DrawPathBean(mTempPath, mTempPaint, mMode);
mPaths.add(mMode);
if (mMode == MODE.DOODLE_MODE) {
mDoodlePath.add(pathBean);
} else if (mMode == MODE.MOSAIC_MODE) {
mMosaicPath.add(pathBean);
}
在Action_Move
时,只要将最后一条路径的path读取出来,移动到手指所到的位置即可:
if (mMode == MODE.DOODLE_MODE && mDoodlePath.size() > 0) {
mDoodlePath.get(mDoodlePath.size() - 1).path.lineTo(mMoveX, mMoveY);
}
然后在Action_Up
的时候,将临时的路径和画笔变量清空,即可:
mTempPath = null;
mTempPaint = null;
最后一步:在onDraw()
中,将该数组中保存的路径绘制出来:
if (mDoodlePath.size() > 0) {
for (DrawPathBean pathBean : mDoodlePath) {
canvas.drawPath(pathBean.path, pathBean.paint);
}
}
-
撤销
有了路径,那么撤销操作就很简单了,只要将数组中最后一条清除,再重绘界面,那么撤销操作就完成了。这里的代码综合了所有操作的撤销动作,涂鸦的只需要看Doodle相关即可:
/**
* 撤销操作
*
* @return 撤销后剩余可以撤销的步骤
*/
public int revertPath() {
int size = mPaths.size();
if (size > 0) {
// 根据最后一位数的mode,删除对应path
MODE lastestMode = mPaths.get(size - 1);
if (lastestMode == MODE.DOODLE_MODE && mDoodlePath.size() > 0) {
mDoodlePath.remove(mDoodlePath.size() - 1);
} else if (lastestMode == MODE.MOSAIC_MODE && mMosaicPath.size() > 0) {
mMosaicPath.remove(mMosaicPath.size() - 1);
} else if (lastestMode == MODE.GRAPH_MODE && mGraphPath.size() > 0) {
mGraphPath.remove(mGraphPath.size() - 1);
}
mPaths.remove(size - 1);
}
postInvalidate();
return size;
}
mPath
是三种路径的总和,不管是涂鸦,图形,或是马赛克,都需要将该操作存入mPath
,然后撤销时,根据存入的类型,对该类型的路径进行相对应的撤销操作。
至此,一个完整的涂鸦功能就完成了~
-
预知图形绘制,移步下一篇章
Android 编辑图片 Canvas画图,涂鸦,马赛克等(二)
Android 编辑图片 Canvas画图,涂鸦,马赛克等(三) -
项目代码
最后奉上完整的项目代码,欢迎clone和star和意见提交:
https://github.com/wx9265661/SmallDemos2
网友评论