Android:使用 onDraw 和 onTouchEvent 绘制线条呈现缓慢
Android: Drawing lines using onDraw and onTouchEvent render slow
我正在尝试使用如下所示的 ontouch 方法和 onDraw 方法绘制四条线:
@Override
protected void onDraw(Canvas canvas) {
initPoints();
path.reset();
path.addCircle(topLeftPoint.x,topLeftPoint.y, 16f,
Path.Direction.CW);
canvas.drawLines(points, paint);
path.addCircle(middleTopPoint.x, middleTopPoint.y, 16f, Path.Direction.CW);
path.addCircle(topRightPoint.x, topRightPoint.y, 16f, Path.Direction.CW);
// canvas.drawLine(topRightPoint.x, topRightPoint.y, bottomRightPoint.x, bottomRightPoint.y, paint);
path.addCircle(bottomRightPoint.x, bottomRightPoint.y, 16f, Path.Direction.CW);
path.addCircle(middleRightPoint.x, middleRightPoint.y, 16f, Path.Direction.CW);
// canvas.drawLine(bottomRightPoint.x, bottomRightPoint.y, bottomLeftPoint.x, bottomLeftPoint.y, paint);
path.addCircle(bottomLeftPoint.x, bottomLeftPoint.y, 16f, Path.Direction.CW);
path.addCircle(middleBottomPoint.x, middleBottomPoint.y, 16f, Path.Direction.CW);
// canvas.drawLine(bottomLeftPoint.x, bottomLeftPoint.y, topLeftPoint.x, topLeftPoint.y, paint);
path.addCircle(topRightPoint.x, topRightPoint.y, 16f, Path.Direction.CW);
path.addCircle(middleLeftPoint.x, middleLeftPoint.y, 16f, Path.Direction.CW);
path.close();
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(final MotionEvent event) {
int action = event.getActionMasked();
if (event.getAction() == MotionEvent.ACTION_DOWN ||
event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_UP) {
float xCoordinate = 16;
float yCoordinate = 16;
if (event.getX() < 16) {
xCoordinate = 16;
} else if (event.getX() > getWidth() - 16) {
xCoordinate = getWidth() - 16;
} else {
xCoordinate = event.getX();
}
if (event.getY() < 16) {
yCoordinate = 16;
} else if (event.getY() > getHeight() - 16) {
yCoordinate = getHeight() - 16;
} else {
yCoordinate = event.getY();
}
if (isInsideTopLeft(event.getX(), event.getY())) {
topLeftPoint.set(xCoordinate, yCoordinate);
middleTopPoint.set((topRightPoint.x + topLeftPoint.x) / 2,
(topRightPoint.y + topLeftPoint.y) / 2);
middleLeftPoint.set((bottomLeftPoint.x + topLeftPoint.x) / 2,
(bottomLeftPoint.y + topLeftPoint.y) / 2);
invalidate();
return true;
} else if (isInsideTopRight(event.getX(), event.getY())) {
topRightPoint.set(xCoordinate, yCoordinate);
middleTopPoint.set((topRightPoint.x + topLeftPoint.x) / 2,
(topRightPoint.y + topLeftPoint.y) / 2);
middleRightPoint.set((bottomRightPoint.x + topRightPoint.x) / 2,
(bottomRightPoint.y + topRightPoint.y) / 2);
invalidate();
return true;
} else if (isInsideBottomRight(event.getX(), event.getY())) {
bottomRightPoint.set(xCoordinate, yCoordinate);
middleBottomPoint.set((bottomLeftPoint.x + bottomRightPoint.x) / 2,
(bottomLeftPoint.y + bottomRightPoint.y) / 2);
middleRightPoint.set((bottomRightPoint.x + topRightPoint.x) / 2,
(bottomRightPoint.y + topRightPoint.y) / 2);
invalidate();
return true;
} else if (isInsideBottomLeft(event.getX(), event.getY())) {
bottomLeftPoint.set(xCoordinate, yCoordinate);
middleBottomPoint.set((bottomLeftPoint.x + bottomRightPoint.x) / 2,
(bottomLeftPoint.y + bottomRightPoint.y) / 2);
middleLeftPoint.set((bottomLeftPoint.x + topLeftPoint.x) / 2,
(bottomLeftPoint.y + topLeftPoint.y) / 2);
invalidate();
return true;
}
}
return super.onTouchEvent(event);
}
但是当我提高触摸速度时,渲染速度变慢了。
我已经使用了路径和线,但性能提升仍然很小。
我从代码中删除的其余方法,例如声明 PointF 对象和使用默认值启动这些对象。
如果有人有任何想法,我将不胜感激。
此致,
AurelianR
如果没有完整的代码,就很难检查可能需要改进的地方。
您正在调用 initPoints() 并在每次绘制调用时重置路径。
如果我们在touch事件中考虑以下情况:
if (isInsideTopLeft(event.getX(), event.getY())) {
// update topLeftPoint, middleTopPoint and middleLeftPoint.
invalidate();
return true;
}
然后在onDraw()
path.reset(); // may be not necessary.
path.addCircle(topLeftPoint.x, topLeftPoint.y, 16f,
Path.Direction.CW); // point changed
path.addCircle(middleTopPoint.x, middleTopPoint.y,16f,Path.Direction.CW);//point changed
path.addCircle(middleLeftPoint.x, middleLeftPoint.y, 16f,Path.Direction.CW);// point changed
只有三个调用有更新rest 6路径更新可以避免。可以使用 postInvalidate(dirtyRect)。
如果您添加完整的代码(连同基本注释),那么我可以通过 运行 检查它。
您的问题与性能无关,与触摸处理执行错误有关。触摸处理概念简述:您的视图会跟随触摸事件
ACTION_DOWN :当用户将手指放在您的视图上时收到(一次性)。始终生成。
ACTION_MOVE :当用户移动手指时收到(多次)。如果用户没有移动手指,则不会生成此事件。
ACTION_UP :当用户将手指从您的视图中移开时收到(一次)。始终生成。
DOWN直到UP完成一个触摸事件周期,用户可以多次触摸你的视图。
您的代码:
if (event.getAction() == MotionEvent.ACTION_DOWN ||
event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_UP){
if(isInsideTopLeft()){
// do something
// return
}
// do same for other cases also.
}
这样你每次都在计算你的案例(isInsideTopLeft() 等),这会导致掉落触摸事件(任何案例都没有涵盖的事件)。您应该做的是在 ACTION_DOWN 中针对特定情况锁定触摸事件,然后只需在 ACTION_MOVE 中移动您的视图,最后在 ACTION_UP 中释放触摸锁定。
工作代码如下:
//create touch lock cases
private final int TOUCH_STATE_UNLOCKED = 0;
private final int TOUCH_STATE_LOCKED_TOP_LEFT = 1;
private final int TOUCH_STATE_LOCKED_TOP_RIGHT = 2;
private final int TOUCH_STATE_LOCKED_BOTTOM_LEFT = 3;
private final int TOUCH_STATE_LOCKED_BOTTOM_RIGHT = 4;
private final int TOUCH_STATE_LOCKED_MIDDLE_LEFT = 5;
private final int TOUCH_STATE_LOCKED_MIDDLE_BOTTOM = 6;
private int TOUCH_STATE = TOUCH_STATE_UNLOCKED;
@Override
public boolean onTouchEvent(final MotionEvent event) {
int action = event.getActionMasked();
float xCoordinate = 16;
float yCoordinate = 16;
int eventX = (int) event.getX();
int eventY = (int) event.getY();
if (eventX < 16) {
xCoordinate = 16;
} else if (eventX > getWidth() - 16) {
xCoordinate = getWidth() - 16;
} else {
xCoordinate = eventX;
}
if (eventY < 16) {
yCoordinate = 16;
} else if (eventY > getHeight() - 16) {
yCoordinate = getHeight() - 16;
} else {
yCoordinate = eventY;
}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
/* Touch event handling in brief, read about touch event handling,
in ACTION_DOWN lock touch event for a particular point.
*/
case MotionEvent.ACTION_DOWN:
// lock touch event for a point . subsequent touch events
if (isInsideTopLeft(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_TOP_LEFT;
} else if (isInsideTopRight(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_TOP_RIGHT;
} else if (isInsideBottomLeft(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_BOTTOM_LEFT;
} else if (isInsideBottomRight(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_BOTTOM_RIGHT;
} else if (isInsideMiddleLeft(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_MIDDLE_LEFT;
} else if (isInsideMiddleBottom(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_MIDDLE_BOTTOM;
}
Log.e(TAG, "onTouchEvent: TOUCH_STATE = " + TOUCH_STATE);
break;
case MotionEvent.ACTION_MOVE:
// simply check for locked case
if (TOUCH_STATE == TOUCH_STATE_LOCKED_TOP_LEFT) {
Log.e(TAG, "onTouchEvent: top left locked");
topLeftPoint.set(xCoordinate, yCoordinate);
middleTopPoint.set((topRightPoint.x + topLeftPoint.x) / 2,
(topRightPoint.y + topLeftPoint.y) / 2);
middleLeftPoint.set((bottomLeftPoint.x + topLeftPoint.x) / 2,
(bottomLeftPoint.y + topLeftPoint.y) / 2);
// working fine with full invalidate also.
invalidate();
}
// handle other cases also
break;
case MotionEvent.ACTION_UP:
TOUCH_STATE = TOUCH_STATE_UNLOCKED; // unlock
}
return true;
}
发现了一个小的性能优化可能性,为此我正在 GitHub 中创建分支并打开一个拉取请求。
我正在尝试使用如下所示的 ontouch 方法和 onDraw 方法绘制四条线:
@Override
protected void onDraw(Canvas canvas) {
initPoints();
path.reset();
path.addCircle(topLeftPoint.x,topLeftPoint.y, 16f,
Path.Direction.CW);
canvas.drawLines(points, paint);
path.addCircle(middleTopPoint.x, middleTopPoint.y, 16f, Path.Direction.CW);
path.addCircle(topRightPoint.x, topRightPoint.y, 16f, Path.Direction.CW);
// canvas.drawLine(topRightPoint.x, topRightPoint.y, bottomRightPoint.x, bottomRightPoint.y, paint);
path.addCircle(bottomRightPoint.x, bottomRightPoint.y, 16f, Path.Direction.CW);
path.addCircle(middleRightPoint.x, middleRightPoint.y, 16f, Path.Direction.CW);
// canvas.drawLine(bottomRightPoint.x, bottomRightPoint.y, bottomLeftPoint.x, bottomLeftPoint.y, paint);
path.addCircle(bottomLeftPoint.x, bottomLeftPoint.y, 16f, Path.Direction.CW);
path.addCircle(middleBottomPoint.x, middleBottomPoint.y, 16f, Path.Direction.CW);
// canvas.drawLine(bottomLeftPoint.x, bottomLeftPoint.y, topLeftPoint.x, topLeftPoint.y, paint);
path.addCircle(topRightPoint.x, topRightPoint.y, 16f, Path.Direction.CW);
path.addCircle(middleLeftPoint.x, middleLeftPoint.y, 16f, Path.Direction.CW);
path.close();
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(final MotionEvent event) {
int action = event.getActionMasked();
if (event.getAction() == MotionEvent.ACTION_DOWN ||
event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_UP) {
float xCoordinate = 16;
float yCoordinate = 16;
if (event.getX() < 16) {
xCoordinate = 16;
} else if (event.getX() > getWidth() - 16) {
xCoordinate = getWidth() - 16;
} else {
xCoordinate = event.getX();
}
if (event.getY() < 16) {
yCoordinate = 16;
} else if (event.getY() > getHeight() - 16) {
yCoordinate = getHeight() - 16;
} else {
yCoordinate = event.getY();
}
if (isInsideTopLeft(event.getX(), event.getY())) {
topLeftPoint.set(xCoordinate, yCoordinate);
middleTopPoint.set((topRightPoint.x + topLeftPoint.x) / 2,
(topRightPoint.y + topLeftPoint.y) / 2);
middleLeftPoint.set((bottomLeftPoint.x + topLeftPoint.x) / 2,
(bottomLeftPoint.y + topLeftPoint.y) / 2);
invalidate();
return true;
} else if (isInsideTopRight(event.getX(), event.getY())) {
topRightPoint.set(xCoordinate, yCoordinate);
middleTopPoint.set((topRightPoint.x + topLeftPoint.x) / 2,
(topRightPoint.y + topLeftPoint.y) / 2);
middleRightPoint.set((bottomRightPoint.x + topRightPoint.x) / 2,
(bottomRightPoint.y + topRightPoint.y) / 2);
invalidate();
return true;
} else if (isInsideBottomRight(event.getX(), event.getY())) {
bottomRightPoint.set(xCoordinate, yCoordinate);
middleBottomPoint.set((bottomLeftPoint.x + bottomRightPoint.x) / 2,
(bottomLeftPoint.y + bottomRightPoint.y) / 2);
middleRightPoint.set((bottomRightPoint.x + topRightPoint.x) / 2,
(bottomRightPoint.y + topRightPoint.y) / 2);
invalidate();
return true;
} else if (isInsideBottomLeft(event.getX(), event.getY())) {
bottomLeftPoint.set(xCoordinate, yCoordinate);
middleBottomPoint.set((bottomLeftPoint.x + bottomRightPoint.x) / 2,
(bottomLeftPoint.y + bottomRightPoint.y) / 2);
middleLeftPoint.set((bottomLeftPoint.x + topLeftPoint.x) / 2,
(bottomLeftPoint.y + topLeftPoint.y) / 2);
invalidate();
return true;
}
}
return super.onTouchEvent(event);
}
但是当我提高触摸速度时,渲染速度变慢了。 我已经使用了路径和线,但性能提升仍然很小。
我从代码中删除的其余方法,例如声明 PointF 对象和使用默认值启动这些对象。
如果有人有任何想法,我将不胜感激。
此致, AurelianR
如果没有完整的代码,就很难检查可能需要改进的地方。 您正在调用 initPoints() 并在每次绘制调用时重置路径。
如果我们在touch事件中考虑以下情况:
if (isInsideTopLeft(event.getX(), event.getY())) {
// update topLeftPoint, middleTopPoint and middleLeftPoint.
invalidate();
return true;
}
然后在onDraw()
path.reset(); // may be not necessary.
path.addCircle(topLeftPoint.x, topLeftPoint.y, 16f,
Path.Direction.CW); // point changed
path.addCircle(middleTopPoint.x, middleTopPoint.y,16f,Path.Direction.CW);//point changed
path.addCircle(middleLeftPoint.x, middleLeftPoint.y, 16f,Path.Direction.CW);// point changed
只有三个调用有更新rest 6路径更新可以避免。可以使用 postInvalidate(dirtyRect)。 如果您添加完整的代码(连同基本注释),那么我可以通过 运行 检查它。
您的问题与性能无关,与触摸处理执行错误有关。触摸处理概念简述:您的视图会跟随触摸事件
ACTION_DOWN :当用户将手指放在您的视图上时收到(一次性)。始终生成。
ACTION_MOVE :当用户移动手指时收到(多次)。如果用户没有移动手指,则不会生成此事件。
ACTION_UP :当用户将手指从您的视图中移开时收到(一次)。始终生成。
DOWN直到UP完成一个触摸事件周期,用户可以多次触摸你的视图。
您的代码:
if (event.getAction() == MotionEvent.ACTION_DOWN ||
event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_UP){
if(isInsideTopLeft()){
// do something
// return
}
// do same for other cases also.
}
这样你每次都在计算你的案例(isInsideTopLeft() 等),这会导致掉落触摸事件(任何案例都没有涵盖的事件)。您应该做的是在 ACTION_DOWN 中针对特定情况锁定触摸事件,然后只需在 ACTION_MOVE 中移动您的视图,最后在 ACTION_UP 中释放触摸锁定。
工作代码如下:
//create touch lock cases
private final int TOUCH_STATE_UNLOCKED = 0;
private final int TOUCH_STATE_LOCKED_TOP_LEFT = 1;
private final int TOUCH_STATE_LOCKED_TOP_RIGHT = 2;
private final int TOUCH_STATE_LOCKED_BOTTOM_LEFT = 3;
private final int TOUCH_STATE_LOCKED_BOTTOM_RIGHT = 4;
private final int TOUCH_STATE_LOCKED_MIDDLE_LEFT = 5;
private final int TOUCH_STATE_LOCKED_MIDDLE_BOTTOM = 6;
private int TOUCH_STATE = TOUCH_STATE_UNLOCKED;
@Override
public boolean onTouchEvent(final MotionEvent event) {
int action = event.getActionMasked();
float xCoordinate = 16;
float yCoordinate = 16;
int eventX = (int) event.getX();
int eventY = (int) event.getY();
if (eventX < 16) {
xCoordinate = 16;
} else if (eventX > getWidth() - 16) {
xCoordinate = getWidth() - 16;
} else {
xCoordinate = eventX;
}
if (eventY < 16) {
yCoordinate = 16;
} else if (eventY > getHeight() - 16) {
yCoordinate = getHeight() - 16;
} else {
yCoordinate = eventY;
}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
/* Touch event handling in brief, read about touch event handling,
in ACTION_DOWN lock touch event for a particular point.
*/
case MotionEvent.ACTION_DOWN:
// lock touch event for a point . subsequent touch events
if (isInsideTopLeft(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_TOP_LEFT;
} else if (isInsideTopRight(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_TOP_RIGHT;
} else if (isInsideBottomLeft(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_BOTTOM_LEFT;
} else if (isInsideBottomRight(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_BOTTOM_RIGHT;
} else if (isInsideMiddleLeft(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_MIDDLE_LEFT;
} else if (isInsideMiddleBottom(event.getX(), event.getY())) {
TOUCH_STATE = TOUCH_STATE_LOCKED_MIDDLE_BOTTOM;
}
Log.e(TAG, "onTouchEvent: TOUCH_STATE = " + TOUCH_STATE);
break;
case MotionEvent.ACTION_MOVE:
// simply check for locked case
if (TOUCH_STATE == TOUCH_STATE_LOCKED_TOP_LEFT) {
Log.e(TAG, "onTouchEvent: top left locked");
topLeftPoint.set(xCoordinate, yCoordinate);
middleTopPoint.set((topRightPoint.x + topLeftPoint.x) / 2,
(topRightPoint.y + topLeftPoint.y) / 2);
middleLeftPoint.set((bottomLeftPoint.x + topLeftPoint.x) / 2,
(bottomLeftPoint.y + topLeftPoint.y) / 2);
// working fine with full invalidate also.
invalidate();
}
// handle other cases also
break;
case MotionEvent.ACTION_UP:
TOUCH_STATE = TOUCH_STATE_UNLOCKED; // unlock
}
return true;
}
发现了一个小的性能优化可能性,为此我正在 GitHub 中创建分支并打开一个拉取请求。