Keep background in DrawingView

8

I need an application to draw on a specific background, the code is working correctly, but when I go to delete / correct a wrong line, it erases the background and the background should be maintained. However, it is deleting the background image together (the lines).

  

INITIAL IMAGE (Before Design)

  

IMAGEWITHSOMETHINGDONE

  

AFTER MAKING A CORRECTION IN DRAWING

  

DrawingViewCode

publicclassDrawingViewextendsViewimplementsView.OnTouchListener{privateCanvasm_Canvas;privatePathm_Path;privatePaintm_Paint;privateArrayList<Pair<Path,Paint>>paths=newArrayList<Pair<Path,Paint>>();privateArrayList<Pair<Path,Paint>>undonePaths=newArrayList<Pair<Path,Paint>>();privatefloatmX,mY;privatestaticfinalfloatTOUCH_TOLERANCE=4;privatebooleanisEraserActive=false;publicDrawingView(Contextcontext,AttributeSetattr){super(context,attr);setFocusable(true);setFocusableInTouchMode(true);//setBackgroundColor(Color.WHITE);//setBackgroundColor(Color.TRANSPARENT);this.setOnTouchListener(this);onCanvasInitialization();}publicvoidonCanvasInitialization(){m_Paint=newPaint();m_Paint.setAntiAlias(true);m_Paint.setDither(true);m_Paint.setColor(Color.parseColor("#000000"));
        m_Paint.setStyle(Paint.Style.STROKE);
        m_Paint.setStrokeJoin(Paint.Join.ROUND);
        m_Paint.setStrokeCap(Paint.Cap.ROUND);
        m_Paint.setStrokeWidth(3);


        m_Canvas = new Canvas();
        m_Path = new Path();
        Paint newPaint = new Paint(m_Paint);
        paths.add(new Pair<Path, Paint>(m_Path, newPaint));

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    public boolean onTouch(View arg0, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (Pair<Path, Paint> p : paths) {
            canvas.drawPath(p.first, p.second);
        }
    }

    private void touch_start(float x, float y) {

        if (isEraserActive) {

            //m_Paint.setColor(Color.WHITE);
            m_Paint.setColor(Color.WHITE);
            //m_Paint.reset();
            m_Paint.setFilterBitmap(true);
            m_Paint.clearShadowLayer();

            m_Paint.setStrokeWidth(20);
            Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
            paths.add(new Pair<Path, Paint>(m_Path, newPaint));

        } else {
            m_Paint.setColor(Color.BLACK);
            m_Paint.setStrokeWidth(3);
            Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
            paths.add(new Pair<Path, Paint>(m_Path, newPaint));

        }


        m_Path.reset();
        m_Path.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            m_Path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        m_Path.lineTo(mX, mY);

        // commit the path to our offscreen
        m_Canvas.drawPath(m_Path, m_Paint);

        // kill this so we don't double draw
        m_Path = new Path();
        Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
        paths.add(new Pair<Path, Paint>(m_Path, newPaint));
    }

    public void activateEraser()
    {
        m_Paint.setColor(Color.TRANSPARENT);
        isEraserActive = true;
    }


    public void deactivateEraser()
    {
        isEraserActive = false;
    }

    public boolean isEraserActive()
    {
        return isEraserActive;
    }


    public void reset()
    {
        paths.clear();

        invalidate();
    }

}

Note: I have already tried Color.TRANSPARENT , but it does not work.

    
asked by anonymous 13.07.2015 / 16:02

1 answer

6

Instead of drawing the paths directly in Canvas View , use another Canvas in> Bitmap and draw on it.

No onDraw() draw this Bitmap on the View canvas .

Declare two new attributes in the DrawingView class:

public class DrawingView extends View implements View.OnTouchListener {

    //Bitmap e Canvas usados para desenhar.
    private Bitmap strokes;
    private Canvas strokeCanvas;

    private Canvas m_Canvas;
    ........
    ........
    ........
}

Create them in method onSizeChanged()

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    //Cria o Bitmap e o Canvas onde o desenho será feito
    if (w != oldw || h != oldh) {
        strokes = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        strokeCanvas = new Canvas(strokes);
    }

    super.onSizeChanged(w, h, oldw, oldh);
}

Change the onDraw method so that the paths are drawn in this Canvas and draw Bitmap in Canvas in View :

@Override
protected void onDraw(Canvas canvas) {

    for (Pair<Path, Paint> p : paths) {
        //As paths são desenhadas no strokeCanvas
        strokeCanvas.drawPath(p.first, p.second);
    }

    //O Bitmap que tem o desenho é desenhado no canvas da view.
    canvas.drawBitmap(strokes,0,0,null);
} 

For testing I used this layout:

Main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btErase"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:text="Erase"
        android:onClick="eraseClicked"/>

    <Button
        android:id="@+id/btDraw"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:text="Draw"
        android:onClick="drawClicked"/>

    <aSua.packageName.DrawingView
        android:id="@+id/drawingView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/fundo" />

</LinearLayout>

With the following Activity:

public class MainActivity extends Activity {

    DrawingView drawingView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        drawingView = (DrawingView)findViewById(R.id.drawingView);
    }

    public void eraseClicked(View view) {
        drawingView.activateEraser();
    }

    public void drawClicked(View view) {
        drawingView.deactivateEraser();
    }

}

It does not have to do with this but during the test I noticed that it was missing to add m_Paint.setXfermode(null); in the method deactivateEraser()

public void deactivateEraser()
{
    m_Paint.setXfermode(null);//<===== Faltava isto
    isEraserActive = false;
}
    
24.07.2015 / 13:59