user3477882
user3477882

Reputation:

Android custom view doesn't draw several times

I added a flag(init) in my on draw that makes a 100x500 rect on View Creation but when i draw my testDraw method from the onTouch method nothing gets drawn.

DrawingView

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


}

Upvotes: 0

Views: 265

Answers (4)

mes
mes

Reputation: 3621

Try this, this is a working example, if you draw anything on canvas, you should call an invalidate() method, to make a view to redraw, also a canvas in the testDraw method doesn't related to view, you should use a canvas from the onDraw parameter, or create a spearate bitmap for it

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

}

Upvotes: 0

JBA
JBA

Reputation: 2909

Suggestion : you should keep the reference of your canvas in order to be able to work on it after onDraw has occured, like this :

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


}

EDIT : according to @Budius you should not do this... so maybe calling the View.invalidate() method will allow you to reload onDraw, then do what you need (?)

Upvotes: 0

Budius
Budius

Reputation: 39856

that's because you're drawing to a different canvas then the one that is been shown on the screen.

The correct way of re-drawing a view is to invalidate it, like this:

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

then on the draw method

   @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 ...
        }
    }

and delete this line Canvas canvas= new Canvas(); the view should not have it's own canvas.

Upvotes: 1

varun bhardwaj
varun bhardwaj

Reputation: 1522

From the SDK Documentation:

onTouch() - This returns a boolean to indicate whether your listener consumes this event. The important thing is that this event can have multiple actions that follow each other. So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event. You need to return true when the ACTION_DOWN event is triggered to indicate that you are interested in the subsequent calls relating to that same event.

I think the problem is that you are returning false from onTouch and that means you are not interested in this event and subsequent action related to it. So I would suggest to return true from this.

Upvotes: 0

Related Questions