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,然后做你需要的 (?)

来自SDK Documentation

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;
}

}