第一种是很顺滑的,在onTouchEvent的ACTION_MOVE事件中也作了重绘的过程,第二种并没有。还有一种情况,在ACTION_MOVE事件中作了监听但是滑动的时候滑的很快,是错误的。
当滑动到②点时,偏移量dx=①点坐标+②点坐标
当滑动到③点时,偏移量dx=①点坐标+③点坐标
........
当滑动到N点时,偏移量dx=①点坐标-N点坐标
由此看出,不管移动到了哪个点,偏移量都是相对于第一次按下的那个点,即ACTION_DOWN中的点坐标。所以在ACTION_MOVE中,需要实时改变图形的几个坐标点,移到①点就将(最初的图形坐标+偏移量=新坐标)赋值给新坐标,②点再次将(最初的图形坐标+偏移量=新坐标)赋值给新坐标.........一直到N点。因为是连续的过程所以看起来就是一连贯的动作,图形也就跟着自然滑动。重绘的时候一定是重绘新坐标(curPtList)而不是最原始的坐标(startPointList)。程序刚运行的时候curPtList和startPointList相同所以第一次绘制是没有问题的。当松开鼠标的时候,ACTION_UP中将最后移动后确定下来的坐标赋给原始坐标startPointList,再滑动的时候重复上面的过程。其实ACTION_UP的作用只是重新赋值给原始坐标,刷新界面所需的坐标点其实是ACTION_MOVE中最后一次移动后所提供的。
之所以会出现滑动会出现上面所说的第三种情况就是因为这个原因,偏移量相对于按下的点,但是改变原始坐标startPointList并每次重新赋值导致移到②点时,再改变startPointList(其实这个时候已经是移到①点后改变了的坐标),再次改变就增加了上一次的偏移量导致会偏远。
ACTION_MOVE中使用这个方法是错误的
List newPointList = new ArrayList<>();
for (Point point : startPointList) {
float newX = point.getX() + dx;
float newY = point.getY() + dy;
Point newPoint = new Point(newX, newY);
newPointList.add(newPoint);
}
startPointList.clear();
startPointList.addAll(newPointList);
完整正确代码
/**
* Created by HASEE on 2017/7/18 12:27
*/
public class DrawTestView extends View {
private List startPointList;
private List curPtList;
private Paint paint;
private Canvas cacheCanvas;
private Bitmap cachebBitmap;
private Path path;
Region re = new Region();
public DrawTestView(Context context) {
super(context);
init();
}
public DrawTestView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawTestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void initData() {
startPointList = new ArrayList<>();
startPointList.add(new Point(50, 50));
startPointList.add(new Point(100, 50));
startPointList.add(new Point(100, 100));
startPointList.add(new Point(200, 100));
startPointList.add(new Point(200, 300));
startPointList.add(new Point(50, 300));
curPtList = new ArrayList<>();
for (Point point : startPointList) {
curPtList.add(new Point(point.getX(), point.getY()));
}
}
public void init() {
initData();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(4);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
cachebBitmap = Bitmap.createBitmap(800, 800, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas(cachebBitmap);
cacheCanvas.drawColor(Color.CYAN);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path = new Path();
path.moveTo(curPtList.get(0).getX(), curPtList.get(0).getY());
for (int i = 1; i < curPtList.size(); i++) {
Point point = curPtList.get(i);
path.lineTo(point.getX(), point.getY());
}
path.close();
canvas.drawBitmap(cachebBitmap, 0, 0, null);
canvas.drawPath(path, paint);
}
private float cur_x, cur_y;
private boolean isMoving;
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
cur_x = x;
cur_y = y;
Log.e("DrawTestView", "DOWN" + cur_x + "/" + cur_y);
//构造一个区域对象,左闭右开的。
RectF r = new RectF();
//计算控制点的边界
path.computeBounds(r, true);
//设置区域路径和剪辑描述的区域
re.setPath(path, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
//在封闭的path内返回true 不在返回false
isMoving = re.contains((int) event.getX(), (int) event.getY());
Log.e("DrawTestView", "--判断点是否则范围内----" + isMoving);
break;
}
case MotionEvent.ACTION_MOVE: {
Log.e("DrawTestView", "MOVE");
if (!isMoving)
break; //return
path.reset();
path.moveTo(x, y);
float dx = x - cur_x;
float dy = y - cur_y;
Log.e("DrawTestView", "UP" + dx + "/" + dy);
for (int i = 0; i < curPtList.size(); i++) {
curPtList.get(i).setX(startPointList.get(i).getX() + dx);
curPtList.get(i).setY(startPointList.get(i).getY() + dy);
}
break;
}
case MotionEvent.ACTION_UP: {
if (!isMoving)
break; //return
// path.reset();
// path.moveTo(x, y);
float dx = x - cur_x;
float dy = y - cur_y;
Log.e("DrawTestView", "UP" + dx + "/" + dy);
List newPointList = new ArrayList<>();
for (Point point : startPointList) {
float newX = point.getX() + dx;
float newY = point.getY() + dy;
Point newPoint = new Point(newX, newY);
newPointList.add(newPoint);
}
startPointList.clear();
startPointList.addAll(newPointList);
break;
}
}
// 通知刷新界面
invalidate();
return true;
}
}
第三种情况下的代码
/**
* Created by HASEE on 2017/7/18 12:27
*/
public class DrawTestView1 extends View {
private List startPointList;
// private List curPtList;
private Paint paint;
private Canvas cacheCanvas;
private Bitmap cachebBitmap;
private Path path;
Region re = new Region();
public DrawTestView1(Context context) {
super(context);
init();
}
public DrawTestView1(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawTestView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void initData() {
startPointList = new ArrayList<>();
startPointList.add(new Point(50, 50));
startPointList.add(new Point(100, 50));
startPointList.add(new Point(100, 100));
startPointList.add(new Point(200, 100));
startPointList.add(new Point(200, 300));
startPointList.add(new Point(50, 300));
//
// curPtList = new ArrayList<>();
//
// for (Point point : startPointList) {
// curPtList.add(new Point(point.getX(), point.getY()));
// }
}
public void init() {
initData();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(4);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
cachebBitmap = Bitmap.createBitmap(800, 800, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas(cachebBitmap);
cacheCanvas.drawColor(Color.CYAN);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path = new Path();
path.moveTo(startPointList.get(0).getX(), startPointList.get(0).getY());
for (int i = 1; i < startPointList.size(); i++) {
Point point = startPointList.get(i);
path.lineTo(point.getX(), point.getY());
}
// path.moveTo(curPtList.get(0).getX(), curPtList.get(0).getY());
// for (int i = 1; i < curPtList.size(); i++) {
// Point point = curPtList.get(i);
// path.lineTo(point.getX(), point.getY());
// }
path.close();
canvas.drawBitmap(cachebBitmap, 0, 0, null);
canvas.drawPath(path, paint);
}
private float cur_x, cur_y;
private boolean isMoving;
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
cur_x = x;
cur_y = y;
Log.e("DrawTestView", "DOWN" + cur_x + "/" + cur_y);
//构造一个区域对象,左闭右开的。
RectF r = new RectF();
//计算控制点的边界
path.computeBounds(r, true);
//设置区域路径和剪辑描述的区域
re.setPath(path, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
//在封闭的path内返回true 不在返回false
isMoving = re.contains((int) event.getX(), (int) event.getY());
Log.e("DrawTestView", "--判断点是否则范围内----" + isMoving);
break;
}
case MotionEvent.ACTION_MOVE: {
Log.e("DrawTestView", "MOVE");
if (!isMoving)
break; //return
path.reset();
path.moveTo(x, y);
float dx = x - cur_x;
float dy = y - cur_y;
Log.e("DrawTestView", "UP" + dx + "/" + dy);
// for (int i = 0; i < curPtList.size(); i++) {
// curPtList.get(i).setX(startPointList.get(i).getX() + dx);
// curPtList.get(i).setY(startPointList.get(i).getY() + dy);
// }
List newPointList = new ArrayList<>();
for (Point point : startPointList) {
float newX = point.getX() + dx;
float newY = point.getY() + dy;
Point newPoint = new Point(newX, newY);
newPointList.add(newPoint);
}
startPointList.clear();
startPointList.addAll(newPointList);
break;
}
case MotionEvent.ACTION_UP: {
if (!isMoving)
break; //return
float dx = x - cur_x;
float dy = y - cur_y;
Log.e("DrawTestView", "UP" + dx + "/" + dy);
List newPointList = new ArrayList<>();
for (Point point : startPointList) {
float newX = point.getX() + dx;
float newY = point.getY() + dy;
Point newPoint = new Point(newX, newY);
newPointList.add(newPoint);
}
startPointList.clear();
startPointList.addAll(newPointList);
break;
}
}
// 通知刷新界面
invalidate();
return true;
}
}