如果需要画图形的话,要提供所绘图形的点的集合,根据各个点进行绘制。 看到onDraw()方法中并没有绘制的过程, 这是因为将绘制过程的方法放在了onTouchEvent的触摸事件中,触摸事件结束有// 更新绘制invalidate()方法,会重新调用onDraw()方法,这个时候mPath就不为空就可以画出图形了。
如果将aOldDraw()放在onDraw()中,如果频繁调用onDraw()方法会不停重复执行aOldDraw()方法,导致内存开销不够。
@Override
protected void onDraw(Canvas canvas) { // TODO: 2017/7/26
super.onDraw(canvas);
mPaint.setColor(Color.BLACK);
canvas.drawPath(mPath, mPaint);
if (isDrawLine) {
mPaint.setColor(Color.RED);
canvas.drawLine(lStartX, lStartY, lStopX, lStopY, mPaint);
}
canvas.drawPath(mPath, mPaint);
if (first != null && second != null) {
mPaint.setColor(Color.RED);
canvas.drawCircle(first.getX(), first.getY(), paintWidth / 2, mPaint);
canvas.drawCircle(second.getX(), second.getY(), paintWidth / 2, mPaint);
}
}
绘制图形过程
public void aOldDraw(List startPointList, Path mPath) {
// TODO: 2017/7/26
mPath.moveTo(startPointList.get(0).getX(), startPointList.get(0).getY());
for (int i = 1; i < startPointList.size(); i++) {
Point point = startPointList.get(i);
mPath.lineTo(point.getX(), point.getY());
}
mPath.close();
}
在画布绘制图形,并可移动某条边改变图形形状,且可以整体移动图形
DrawPolygonView2
public class DrawPolygonView2 extends View {
private static int HORIZONTAL = 0; //水平方向
private static int VERTICAL = 1; //垂直方向
private static int ISNOTHORORVER = 7; //不是水平也不是垂直
int orientation = ISNOTHORORVER; //0表示水平方向,1表示垂直方向
private Context context;
private List points = new ArrayList<>();//添加点的集合
private List intentPoints = new ArrayList<>();//传输点的集合
private Paint mPaint = new Paint();//画笔
private Path mPath = new Path();//路径
float x;//上一个拐点x
float y;//上一个拐点y
//当前点
float newX;
float newY;
private float startX;//开始点
private float startY;//开始点
private float lastX;//结束点
private float lastY;//结束点
//起点
private float firstX;
private float firstY;
private List flag;//判断手指移动方向的集合
private boolean drawAble = true;//判断是否可画图
boolean isRemoveStartPoint;//是否移除开始点
private int downPosition;//确定按下的点是执行移动线还是移动view
private Point duan1;//选中线的端点1
private Point duan2;//选中线的端点2
private float lStartX;//drawLine的开始点
private float lStartY;
private float lStopX;//drawLine的结束点
private float lStopY;
public List getPoints() {
return intentPoints;
}
public DrawPolygonView2(Context context) {
super(context);
init(context);
}
public DrawPolygonView2(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DrawPolygonView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**
* 初始化
*
* @param context
*/
private void init(Context context) {
this.context = context;
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(10);
mPaint.setStyle(Paint.Style.STROKE);
//初始化时设置存放标识方向的list
flag = new ArrayList<>();
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.BLACK);
canvas.drawPath(mPath, mPaint);
if (isDrawLine) {
mPaint.setColor(Color.RED);
canvas.drawLine(lStartX, lStartY, lStopX, lStopY, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
if (drawAble) {
actionDown(e);
} else {//已经完成绘图时判断落点位置
startX = e.getX();
startY = e.getY();
if (intentPoints.size() >= 2) {
downPosition = ensurePoint(startX, startY);
} else {
drawAble = true;
}
}
break;
case MotionEvent.ACTION_MOVE:
if (drawAble) {
actionMove(e);
} else {//已经完成绘图时根据落点位置执行 移动线或view整体
lastX = e.getX();
lastY = e.getY();
moveLine(lastX - startX, lastY - startY);
startX = lastX;
startY = lastY;
}
break;
case MotionEvent.ACTION_UP:
if (drawAble) {
actionUp(e);
}
drawAble = false;//抬手后不可编辑
break;
}
// 更新绘制
invalidate();
return true;
}
/**
* 确定点击点
*
* @param startX 按下时的X
* @param startY 按下时的Y
* @return
*/
private int ensurePoint(float startX, float startY) {
//形成的多边形要首尾相接
List pp = new ArrayList<>();
pp.addAll(intentPoints);
pp.add(intentPoints.get(0)); // TODO: 2017/7/24
int position = -1;
double minL = DrawUtils.pointToLine(startX, startY, movePoints.get(movePoints.size() - 1), movePoints.get(0));
for (int i = 0; i < movePoints.size() - 1; i++) {
double l1 = DrawUtils.pointToLine(startX, startY, movePoints.get(i), movePoints.get(i + 1));
if (minL < l1) {
} else if (minL > l1) {
position = i;
minL = l1;
}
}
if (minL <= 40) {
return position;//根据position获取要移动线的 端点
} else if (DrawUtils.PtInRegion(new Point(startX, startY), pp) == 1 && minL > 40) {
return -2;//表示点击点在多边形内,执行移动view
} else {
return -3;//表示点击点在多边形外,不执行任何操作
}
}
/**
* 手指按下
*
* @param e
*/
private void actionDown(MotionEvent e) {
float mx = e.getX();
float my = e.getY();
mPath.reset();
startX = mx;
startY = my;
mPath.moveTo(mx, my);
x = mx;
y = my;
firstX = mx;
firstY = my;
points.add(new Point(startX, startY));
}
/**
* 手指滑动
*
* @param e
*/
int horizontalCount = 1;
int verticalCount = 1;
private void actionMove(MotionEvent e) {
lastX = e.getX();
lastY = e.getY();
//当前点与上一个拐点比较
float dx = lastX - x;
float dy = lastY - y;
//两点之间的距离大于等于2时判读方向
if (Math.abs(lastX - startX) > 2 || Math.abs(lastY - startY) > 2) {
//判断水平方向
if (Math.abs(lastX - startX) > Math.abs(lastY - startY)) {
//上个方向是垂直且flag集合中都是垂直记录则方向发生变化
if (orientation == VERTICAL && !flag.contains(HORIZONTAL)) {
//保存拐点
points.add(new Point(newX, newY));
//赋值成上一个拐点
x = newX;
y = newY;
//path重新绘制,既纠正前面的拐点
mPath.reset();
mPath.moveTo(firstX, firstY);
for (Point point : points) {
mPath.lineTo(point.getX(), point.getY());
invalidate();
}
}
//水平方向
orientation = HORIZONTAL;
//flag方向标识的添加和移除更新flag
flag.add(0, orientation);
Log.e("DrawPolygonView2", "水平方向:" + horizontalCount);
horizontalCount++;
flag.remove(flag.size() - 1);
//当距离变化超过20时更新可能成为当前拐点的x,y
if (Math.abs(dx) > 20 || Math.abs(dy) > 20) {
newY = y;
newX = lastX;
mPath.lineTo(newX, newY);
}
} else if (Math.abs(lastX - startX) < Math.abs(lastY - startY)) {//垂直方向
if (orientation == HORIZONTAL && !flag.contains(VERTICAL)) {
points.add(new Point(newX, newY));
//赋值上一个拐点
x = newX;
y = newY;
//path重新绘制,既纠正前面的拐点
mPath.reset();
mPath.moveTo(firstX, firstY);
for (Point point : points) {
mPath.lineTo(point.getX(), point.getY());
invalidate();
}
}
orientation = VERTICAL;
flag.add(0, orientation);
Log.e("DrawPolygonView2", "垂直方向:" + verticalCount);
verticalCount++;
flag.remove(flag.size() - 1);
//当距离变化超过20时更新可能成为当前拐点的x,y
if (Math.abs(dx) > 20 || Math.abs(dy) > 20) {
newX = x;
newY = lastY;
mPath.lineTo(newX, newY);
}
}
} else {
}
//更新一点的点
startX = lastX;
startY = lastY;
}
/**
* 手指抬起
*
* @param e
*/
private void actionUp(MotionEvent e) {
if (points.size() >= 2) {
closePolygon();
intentPoints.clear();
intentPoints.addAll(points);
points.clear();
//判断去除几个起点
if (isRemoveStartPoint) {
intentPoints.remove(0);
intentPoints.remove(intentPoints.size() - 1);
} else {
intentPoints.remove(0);
}
anewDraw(intentPoints, mPath);
movePoints.clear();
movePoints.addAll(intentPoints);
} else {
// intentPoints.add(new Point(firstX, firstY));
// if (!flag.contains(1)) {
// intentPoints.add(new Point(lastX, y));
// } else {
// intentPoints.add(new Point(x, lastY));
// }
}
}
/**
* 闭合多边形
*/
public void closePolygon() {
//多边形点的集合
List polygonPoints = new ArrayList<>();
polygonPoints.addAll(points);
Point second = points.get(1);
// if (!flag.contains(VERTICAL)) {//水平 // TODO: 2017/7/25
if (!flag.subList(1, 5).contains(VERTICAL)) {//水平
//形成多边形集合
polygonPoints.add(new Point(lastX, y)); //抬手点
polygonPoints.add(new Point(firstX, firstY)); //起点
//起点和抬手点可以获得2个点
Point p1 = new Point(firstX, y);
Point p2 = new Point(lastX, firstY);
Log.e("DrawPolygonView2", "水平方向"+"firstX:" + firstX+"/"+"y:" + y+
"\nlastX:"+lastX+"firstY:"+firstY);
if (DrawUtils.PtInRegion(p2, polygonPoints) == -1) {//p2在多变形外
//判断是否添加抬手点
List t2 = new ArrayList<>();//点p2和点(x,y)的线段
t2.add(p2);
t2.add(new Point(x, y));
List z2 = new ArrayList<>();//p2和抬手点的线段
z2.add(p2);
z2.add(new Point(lastX, y)); //抬手点
if (DrawUtils.PtInRegion(new Point(lastX, y), t2) != 0
&& DrawUtils.PtInRegion(new Point(x, y), z2) != 0) {
points.add(new Point(lastX, y));
}
points.add(p2);
points.add(new Point(firstX, firstY));
//起点添加判断
List s2 = new ArrayList<>();
s2.add(p2);
s2.add(second);
List q2 = new ArrayList<>();
q2.add(p2);
q2.add(new Point(firstX, firstY));
if (DrawUtils.PtInRegion(new Point(firstX, firstY), s2) == 0
|| DrawUtils.PtInRegion(second, q2) == 0) {
isRemoveStartPoint = true;
}
} else {
List t1 = new ArrayList<>();
t1.add(p1);
t1.add(new Point(x, y));
List z1 = new ArrayList<>();//p1和抬手点的线段
z1.add(p1);
z1.add(new Point(lastX, y));
if (DrawUtils.PtInRegion(new Point(lastX, y), t1) != 0
&& DrawUtils.PtInRegion(new Point(x, y), z1) != 0) {
points.add(new Point(lastX, y));
}
points.add(p1);
points.add(new Point(firstX, firstY));
//起点添加判断
List s1 = new ArrayList<>();
s1.add(p1);
s1.add(second);
List q1 = new ArrayList<>();
q1.add(p1);
q1.add(new Point(firstX, firstY));
if (DrawUtils.PtInRegion(new Point(firstX, firstY), s1) == 0
|| DrawUtils.PtInRegion(second, q1) == 0) {
isRemoveStartPoint = true;
}
}
// } else if (!flag.contains(HORIZONTAL)) {//垂直
} else if (!flag.subList(1, 5).contains(HORIZONTAL)) {//垂直
//形成多边形集合
polygonPoints.add(new Point(x, lastY));
polygonPoints.add(new Point(firstX, firstY));
//获得2个点
Point p1 = new Point(firstX, lastY);
Point p2 = new Point(x, firstY);
Log.e("DrawPolygonView2", "垂直方向"+"firstX:" + firstX+"/"+"lastY:" + lastY+
"\nx:"+x+"firstY:"+firstY);
if (DrawUtils.PtInRegion(p2, polygonPoints) == -1) {//p2在多变形外
//判断是否添加抬手点
List t2 = new ArrayList<>();
t2.add(p2);
t2.add(new Point(x, y));
List z2 = new ArrayList<>();//p2和抬手点的线段
z2.add(p2);
z2.add(new Point(x, lastY));
if (DrawUtils.PtInRegion(new Point(x, lastY), t2) != 0
&& DrawUtils.PtInRegion(new Point(x, y), z2) != 0) {
points.add(new Point(x, lastY));
}
points.add(p2);
points.add(new Point(firstX, firstY));
//起点添加判断
List s2 = new ArrayList<>();
s2.add(p2);
s2.add(second);
List q2 = new ArrayList<>();
q2.add(p2);
q2.add(new Point(firstX, firstY));
if (DrawUtils.PtInRegion(new Point(firstX, firstY), s2) == 0
|| DrawUtils.PtInRegion(second, q2) == 0) {
isRemoveStartPoint = true;
}
} else {
//判断是否添加抬手点
List t1 = new ArrayList<>();
t1.add(p1);
t1.add(new Point(x, y));
List z1 = new ArrayList<>();//p1和抬手点的线段
z1.add(p1);
z1.add(new Point(x, lastY));
if (DrawUtils.PtInRegion(new Point(x, lastY), t1) != 0
&& DrawUtils.PtInRegion(new Point(x, y), z1) != 0) {
points.add(new Point(x, lastY));
}
points.add(p1);
points.add(new Point(firstX, firstY));
//起点添加判断
List s1 = new ArrayList<>();
s1.add(p1);
s1.add(second);
List q1 = new ArrayList<>();
q1.add(p1);
q1.add(new Point(firstX, firstY));
if (DrawUtils.PtInRegion(new Point(firstX, firstY), s1) == 0
|| DrawUtils.PtInRegion(second, q1) == 0) {
isRemoveStartPoint = true;
}
}
}
}
/**
* 选中整体图形后移动并重新绘制
*
* @param points 点集合
*/
public void anewDraw(List points, Path mPath) {
mPath.reset();
mPath.moveTo(points.get(0).getX(), points.get(0).getY());
for (Point point : points) {
mPath.lineTo(point.getX(), point.getY());
}
mPath.lineTo(points.get(0).getX(), points.get(0).getY());
invalidate();
}
/**
* 重绘选中直线后图形
*
* @param points
*/
List linePoints = new ArrayList<>();
boolean isDrawLine;//是否划线
public void drawLine(List points) {
isDrawLine = true;
mPath.reset();
mPath.moveTo(points.get(downPosition + 1).getX(), points.get(downPosition + 1).getY());
linePoints.clear();
for (int i = downPosition + 1; i < points.size(); i++) { //画选中那条线(红线)的下半部分
linePoints.add(points.get(i));
}
for (int i = 0; i < downPosition + 1; i++) { //画选中那条线(红线)的上半部分
linePoints.add(points.get(i));
}
for (Point point : linePoints) { //画红线
mPath.lineTo(point.getX(), point.getY());
}
lStartX = duan1.getX();
lStartY = duan1.getY();
lStopX = duan2.getX();
lStopY = duan2.getY();
invalidate();
}
/**
* 移动VIEW
*
* @param dx
* @param dy
*/
public void moveView(float dx, float dy) {
for (Point p : movePoints) {
p.setX(p.getX() + dx);
p.setY(p.getY() + dy);
}
isDrawLine = false;
anewDraw(movePoints, mPath);
intentPoints.clear();
intentPoints.addAll(movePoints);
}
/**
* 移动线
*
* @param startX
* @param startY
* @param dx
* @param dy
*/
List movePoints = new ArrayList<>();//用于存放变化的点
public void moveLine(float dx, float dy) {
movePoints.clear();
movePoints.addAll(intentPoints);
int position = downPosition;
//通过ensurePoint获得position,判断position
if (position == -1) { //选中倒数第二个点和起点的那条直线
duan1 = movePoints.get(movePoints.size() - 1);
duan2 = movePoints.get(0);
} else if (position == -2) { //选中整体图形
moveView(dx, dy);
return;
} else if (position == -3) { //表示点击点在多边形外,不执行任何操作
return;
} else { //表示选中其他的边
duan1 = movePoints.get(position);
duan2 = movePoints.get(position + 1);
}
//线段垂直,只能左右平移
if (duan1.getX() == duan2.getX()) {
duan1.setX(duan1.getX() + dx);
duan2.setX(duan2.getX() + dx);
}
//线段水平,只能上下平移
if (duan1.getY() == duan2.getY()) {
duan1.setY(duan1.getY() + dy);
duan2.setY(duan2.getY() + dy);
}
if (position == -1) {
movePoints.set(movePoints.size() - 1, duan1);
movePoints.set(0, duan2);
} else {
movePoints.set(position, duan1);
movePoints.set(position + 1, duan2);
}
drawLine(movePoints);
intentPoints.clear();
intentPoints.addAll(movePoints);
}
/**
* 清除画板
*/
public void cleanDraw() {
mPath.reset();
movePoints.clear();
intentPoints.clear();
points.clear();
orientation = ISNOTHORORVER;
drawAble = true;
isDrawLine = false;
isRemoveStartPoint = false;
flag.clear();
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
flag.add(orientation);
invalidate();
}
}