2
votes

I have a canvas which allows user to draw and save. It also allows user to change color and draw on the same canvas with different colors.

My Paint class:

package com.test.testing;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.test.testing.*;

public class CustomView extends View {
    Paint paint;
    Path path;
    float x = 0;
    float y = 0;
    private int cWhite = Color.WHITE;
    private Button btnS, btnSa;

    public CustomView(Context context) {
        super(context);
        paint = new Paint();
        path= new Path();
        paint.setAlpha(255);
        paint.setColor(cWhite);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(20);

        btnS = (Button)((FreeDraw) context).findViewById(R.id.shareButton);
        btnSa = (Button)((FreeDraw) context).findViewById(R.id.saveButton);
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path,paint);
        canvas.drawCircle(x, y, 10, paint);
    }

    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            path.moveTo(event.getX(), event.getY());
            path.lineTo(event.getX(), event.getY());
            if (btnS.getVisibility() == View.VISIBLE && btnS != null) {
                //if share button is displaying but I drew something else
                //the share button should disappear and I should be presented
                //with the save button

                btnS.setVisibility(View.GONE);
                btnSa.setVisibility(View.VISIBLE);
            }
            if (btnSa.getVisibility() == View.VISIBLE && btnS != null) {
                //do nothing...
            }
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            x = event.getX();
            y = event.getY();
            path.lineTo(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            path.lineTo(event.getX(), event.getY());
            invalidate();
            break;
        case MotionEvent.ACTION_CANCEL:
            break;
        default:
            break;
        }
        return true;
    }
}

In my Activity I call the Paint class and use an XML layout like this:

layout = (FrameLayout)findViewById(R.id.viewd);
//layout.removeAllViews();
view = new CustomView(FreeDraw.this);
view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
layout.addView(view);

Also in the same activity I have the following code which handles the color changing:

public void colorHandle() {
    // custom dialog
    final Dialog dialog = new Dialog(this);
    dialog.setContentView(R.layout.colorlayout);
    dialog.setTitle("Choose a Drawing Color");

    Button btnWH = (Button) dialog.findViewById(R.id.btnWhite);
    Button btnBL = (Button) dialog.findViewById(R.id.btnBlack);
    Button btnBLU = (Button) dialog.findViewById(R.id.btnBlue);
    Button btnCY = (Button) dialog.findViewById(R.id.btnCyan);
    Button btnDG = (Button) dialog.findViewById(R.id.btnDkGray);
    Button btnGR = (Button) dialog.findViewById(R.id.btnGray);
    Button btnGRE = (Button) dialog.findViewById(R.id.btnGreen);
    Button btnLG = (Button) dialog.findViewById(R.id.btnLtGray);
    Button btnMG = (Button) dialog.findViewById(R.id.btnMagenta);
    Button btnRD = (Button) dialog.findViewById(R.id.btnRed);
    Button btnYE = (Button) dialog.findViewById(R.id.btnYellow);

    if (btnWH != null) {
        btnWH.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.WHITE);
                dialog.dismiss();
            }
        });
    }
    if (btnBL != null) {
        btnBL.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.BLACK);
                dialog.dismiss();
            }
        });
    }
    if (btnBLU != null) {
        btnBLU.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.BLUE);
                dialog.dismiss();
            }
        });
    }
    if (btnCY != null) {
        btnCY.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.CYAN);
                dialog.dismiss();
            }
        });
    }
    if (btnDG != null) {
        btnDG.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.DKGRAY);
                dialog.dismiss();
            }
        });
    }
    if (btnGR != null) {
        btnGR.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.GRAY);
                dialog.dismiss();
            }
        });
    }
    if (btnGRE != null) {
        btnGRE.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.GREEN);
                dialog.dismiss();
            }
        });
    }
    if (btnLG != null) {
        btnLG.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.LTGRAY);
                dialog.dismiss();
            }
        });
    }
    if (btnMG != null) {
        btnMG.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.MAGENTA);
                dialog.dismiss();
            }
        });
    }
    if (btnRD != null) {
        btnRD.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.RED);
                dialog.dismiss();
            }
        });
    }
    if (btnYE != null) {
        btnYE.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                layout = (FrameLayout)findViewById(R.id.viewd);
                //layout.removeAllViews();
                view = new CustomView(FreeDraw.this);
                view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
                layout.addView(view);
                view.paint.setColor(Color.YELLOW);
                dialog.dismiss();
            }
        });
    }
    dialog.show();
}

I have to repeat the following code for each color because once I draw something and change color and draw something else, all the previous drawn path changes to the new color and this code fixed it:

        layout = (FrameLayout)findViewById(R.id.viewd);
        //layout.removeAllViews();
        view = new CustomView(FreeDraw.this);
        view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        layout.addView(view);

My save image portion of the code in the Activity is:

View.OnClickListener saveHandle = new View.OnClickListener() {
    public void onClick(View v) {
        new SaveImageTask().execute(null, null, null);
    }
};
public class SaveImageTask extends AsyncTask<Void, Void, Void> {
     @Override
     protected Void doInBackground(Void... params) { //Running in background
        View content = layout;
        content.setDrawingCacheEnabled(true);
        content.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        Bitmap bitmap = content.getDrawingCache();
        File folder = new File(Environment.getExternalStorageDirectory() + "/PB");
        if (!folder.exists()) {
            folder.mkdir();
        }
        file = new File(folder + "/pb_image_" + Math.random()  + ".png");
        FileOutputStream ostream;
        try {
            file.createNewFile();
            ostream = new FileOutputStream(file);
            bitmap.compress(CompressFormat.PNG, 100, ostream);
            ostream.flush();
            ostream.close();
            isSaved = true;
        } catch (Exception e) {
            e.printStackTrace();
            isSaved = false;
        }
        return null;
     }

     @Override
     protected  void onPreExecute() { //Activity is on progress
         //displayToast("Your image is saving...");
         btnSave.setVisibility(View.GONE);
         btnShare.setVisibility(View.GONE);
         pb.setVisibility(View.VISIBLE);
     }

     @Override
     protected void onPostExecute(Void v) { //Activity is done...
        if (isSaved == true) {
             displayToast("Image was saved.");
             btnSave.setVisibility(View.GONE);
             btnShare.setVisibility(View.VISIBLE);
             pb.setVisibility(View.GONE);
         }
         if (isSaved == false) {
             displayToast("Unable to save image. Try again later.");
             btnSave.setVisibility(View.VISIBLE);
             btnShare.setVisibility(View.GONE);
             pb.setVisibility(View.GONE);
         }
     }
}

What I am looking to do is:

  • When I draw something and SAVE the image, the SHARE button should appear and the Canvas shouldn't clear (working)
  • While the SHARE button is visible I draw something else on the canvas the SAVE button should reappear (working)
  • When I press the SAVE button again it should save the new canvas drawings (Not working, it is saving the previously drawn canvas which I saved in the first step)

How can I modify my codes to do this:

  • Do not create new canvas for each color, rather create new paths.
  • Once the drawing on the canvas is saved, and I draw something new on top of the existing canvas and save. The new canvas should be saved with all the old and new drawn paths
  • Clear the entire canvas if ERASE button is pressed
1

1 Answers

4
votes

Do not create new canvas for each color, rather create new paths.

Create Path's for every new time the user touches the canvas and theoretically draws something. Store that new path along with its color and in the onDraw method iterate over the path structure and draw each of the paths with its saved color:

// this will hold the data of each path the user draws
class DrawnItem {
    int color = Color.GREEN; // default values
    Path line = new Path();
}

Paint paint;
int mCurrentColor = Color.GREEN; // start with green
ArrayList<DrawnItem> mDrawings = new ArrayList<DrawnItem>();

// in the onDraw method:
protected void onDraw(Canvas canvas) {
    final int count = mDrawings.size();
    for (int i = 0; i < count; i++) {
        final DrawnItem item = mDrawings.get(i);
        paint.setColor(item.color);
        canvas.drawPath(item.line, paint);
    }
    paint.setColor(mCurrentColor);
    canvas.drawCircle(x, y, 10, paint);
}

private DrawnItem mCurrentItem = null;

// and in the onTouch method:
public boolean onTouchEvent(MotionEvent event) {
    final int action = event.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
       // the user started a new drawing so build a new DrawnItem
       mCurrentItem = new DrawnItem();
       mCurrentitem.color= mCurrentColor;  
       mDrawings.add(mCurrentItem);
       // use the item.line to setup the Path with the x and y values
       // .... 
       invalidate();
       break; 
       case MotionEvent.ACTION_MOVE:
           x = event.getX();
           y = event.getY();
           mCurrentItem.line.lineTo(x, y);
           invalidate();
       break;
    case MotionEvent.ACTION_UP:
        mCurrentItem.line.lineTo(event.getX(), event.getY());
        mCurrentItem = null;
        invalidate();
        break;
    case MotionEvent.ACTION_CANCEL:
        mCurrentItem = null; // this drawing session was canceled so this DrawnItem is now closed
        break;
    default:
        break;

Now, in your dialog, the only thing you need to do is to update the mCurrentColor of the custom view to point of the chosen color and from that point on the path will be drawn with the dedicated color. If the user switches the color to a previous stored color then the path corresponding for that color will be selected.

Code for saving the view as a Bitmap in the doInBackground():

Bitmap bitmap = Bitmap.createBitmap(layout.getWidth(), layout.getHeight(), Bitmap.Config. RGB_565);
Canvas canvas = new Canvas(bitmap);
layout.draw(canvas);

Clear the entire canvas if ERASE button is pressed

Clear the previous path structure and call invalidate() on your custom view:

mDrawings.clear();
customView.invalidate();