Android 自定义视图没有多次绘制
Android custom view doesn't draw several times
我在绘制时添加了一个标志 (init),它在视图创建时创建了一个 100x500 的矩形,但是当我从 onTouch 方法绘制我的 testDraw 方法时,没有绘制任何东西。
绘图视图
class DrawingView extends View{
Canvas canvas= new Canvas();;
Paint paint= new Paint();
boolean init;
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
paint.setColor(Color.argb(255, 0, 255, 0));
this.init = true;
}
public void testDraw(){
canvas.drawRect(0,0,500,500,paint);
}
@Override
public void onDraw(Canvas canvas){
if(this.init == true){
canvas.drawRect(0,0,500,100,paint);
this.init = false;
}else{
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
testDraw();
}
return false;
}
}
建议:您应该保留 canvas 的引用以便能够在 onDraw 发生后对其进行处理,如下所示:
class DrawingView extends View{
Canvas your_canvas= new Canvas(); /* change the variable name */
Paint paint= new Paint();
boolean init;
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
paint.setColor(Color.argb(255, 0, 255, 0));
this.init = true;
}
public void testDraw(){
your_canvas.drawRect(0,0,500,500,paint); /* changed variable name */
}
@Override
public void onDraw(Canvas canvas){
if(this.init == true){
your_canvas = canvas; /* keep canvas reference in your_canvas variable */
canvas.drawRect(0,0,500,100,paint);
this.init = false;
}else{
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
testDraw();
}
return false;
}
}
编辑:根据@Budius,你不应该这样做......所以也许调用 View.invalidate() 方法将允许你重新加载 onDraw,然后做你需要的 (?)
onTouch() - 此 return 是一个布尔值,指示您的侦听器是否使用此事件。重要的是这个事件可以有多个相互跟随的动作。因此,如果您在收到向下操作事件时 return false,则表明您尚未使用该事件并且对该事件的后续操作也不感兴趣。因此,您不会被要求执行事件中的任何其他操作,例如手指手势或最终的向上操作事件。
当触发 ACTION_DOWN 事件时,您需要 return true 以表明您对与同一事件相关的后续调用感兴趣。
我认为问题在于您从 onTouch returning false,这意味着您对此事件以及与之相关的后续操作不感兴趣。所以我建议 return true 从这个。
那是因为您绘制的 canvas 与屏幕上显示的不同。
重新绘制视图的正确方法是使其无效,如下所示:
private boolean testDrawn = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
testDrawn = true;
invalidate(); // << this will make on drawn be called again
}
return false;
}
然后在draw方法上
@Override
public void onDraw(Canvas canvas){
if(this.init == true){
canvas.drawRect(0,0,500,100,paint);
this.init = false;
}else if(testDrawn){
testDrawn = false;
// do the drawing here ...
}
}
并删除这一行 Canvas canvas= new Canvas();
视图不应该有它自己的 canvas。
试试这个,这是一个工作示例,如果你在 canvas 上绘制任何东西,你应该调用一个 invalidate() 方法,使视图重绘,也在 canvas testDraw 方法与视图无关,您应该使用 onDraw 参数中的 canvas,或者为其创建一个单独的位图
public class DrawingView extends View {
private Bitmap cachedBitmap;
private Canvas cachedCanvas;
private Paint linePaint;
private boolean isClicked;
private float lastX;
private float lastY;
public DrawingView(Context context) {
super(context);
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
if(cachedBitmap == null && width > 0 && height > 0) {
cachedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
cachedCanvas = new Canvas(cachedBitmap);
linePaint = new Paint();
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(3);
linePaint.setColor(Color.parseColor("#000000"));
}
canvas.drawBitmap(cachedBitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isClicked = true;
break;
case MotionEvent.ACTION_MOVE:
if(isClicked && cachedCanvas != null) {
cachedCanvas.drawLine(lastX, lastY, event.getX(), event.getY(), linePaint);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
isClicked = false;
break;
}
lastX = event.getX();
lastY = event.getY();
return true;
}
}
我在绘制时添加了一个标志 (init),它在视图创建时创建了一个 100x500 的矩形,但是当我从 onTouch 方法绘制我的 testDraw 方法时,没有绘制任何东西。
绘图视图
class DrawingView extends View{
Canvas canvas= new Canvas();;
Paint paint= new Paint();
boolean init;
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
paint.setColor(Color.argb(255, 0, 255, 0));
this.init = true;
}
public void testDraw(){
canvas.drawRect(0,0,500,500,paint);
}
@Override
public void onDraw(Canvas canvas){
if(this.init == true){
canvas.drawRect(0,0,500,100,paint);
this.init = false;
}else{
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
testDraw();
}
return false;
}
}
建议:您应该保留 canvas 的引用以便能够在 onDraw 发生后对其进行处理,如下所示:
class DrawingView extends View{
Canvas your_canvas= new Canvas(); /* change the variable name */
Paint paint= new Paint();
boolean init;
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
paint.setColor(Color.argb(255, 0, 255, 0));
this.init = true;
}
public void testDraw(){
your_canvas.drawRect(0,0,500,500,paint); /* changed variable name */
}
@Override
public void onDraw(Canvas canvas){
if(this.init == true){
your_canvas = canvas; /* keep canvas reference in your_canvas variable */
canvas.drawRect(0,0,500,100,paint);
this.init = false;
}else{
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
testDraw();
}
return false;
}
}
编辑:根据@Budius,你不应该这样做......所以也许调用 View.invalidate() 方法将允许你重新加载 onDraw,然后做你需要的 (?)
onTouch() - 此 return 是一个布尔值,指示您的侦听器是否使用此事件。重要的是这个事件可以有多个相互跟随的动作。因此,如果您在收到向下操作事件时 return false,则表明您尚未使用该事件并且对该事件的后续操作也不感兴趣。因此,您不会被要求执行事件中的任何其他操作,例如手指手势或最终的向上操作事件。 当触发 ACTION_DOWN 事件时,您需要 return true 以表明您对与同一事件相关的后续调用感兴趣。
我认为问题在于您从 onTouch returning false,这意味着您对此事件以及与之相关的后续操作不感兴趣。所以我建议 return true 从这个。
那是因为您绘制的 canvas 与屏幕上显示的不同。
重新绘制视图的正确方法是使其无效,如下所示:
private boolean testDrawn = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
testDrawn = true;
invalidate(); // << this will make on drawn be called again
}
return false;
}
然后在draw方法上
@Override
public void onDraw(Canvas canvas){
if(this.init == true){
canvas.drawRect(0,0,500,100,paint);
this.init = false;
}else if(testDrawn){
testDrawn = false;
// do the drawing here ...
}
}
并删除这一行 Canvas canvas= new Canvas();
视图不应该有它自己的 canvas。
试试这个,这是一个工作示例,如果你在 canvas 上绘制任何东西,你应该调用一个 invalidate() 方法,使视图重绘,也在 canvas testDraw 方法与视图无关,您应该使用 onDraw 参数中的 canvas,或者为其创建一个单独的位图
public class DrawingView extends View {
private Bitmap cachedBitmap;
private Canvas cachedCanvas;
private Paint linePaint;
private boolean isClicked;
private float lastX;
private float lastY;
public DrawingView(Context context) {
super(context);
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
if(cachedBitmap == null && width > 0 && height > 0) {
cachedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
cachedCanvas = new Canvas(cachedBitmap);
linePaint = new Paint();
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(3);
linePaint.setColor(Color.parseColor("#000000"));
}
canvas.drawBitmap(cachedBitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isClicked = true;
break;
case MotionEvent.ACTION_MOVE:
if(isClicked && cachedCanvas != null) {
cachedCanvas.drawLine(lastX, lastY, event.getX(), event.getY(), linePaint);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
isClicked = false;
break;
}
lastX = event.getX();
lastY = event.getY();
return true;
}
}