I am trying to make an application where user can either choose to blur the image or can choose to paint on the screen (user can also do both of these at one canvas).
I have it pretty much working however, I am having a strange issue with the drawing on a first draw after the mode is changed from blur to paint or vice versa.
Please see the image below.
PAINT MODE
The paths drawn vertically is when user has paint mode selected. As you can see the first path contains paint from both blur paint object as well paint object (with red stroke). Any subsequent paths drawn now works fine.
BLUR MODE
Similarly you can see, after drawing two vertical paths, user switches the mode to blur and draws horizontal paths in this mode. This time similar to above first path is a mixture of two paint objects and subsequent paths works fine.
Please see the code posted below and It would be great if you can suggest what could be causing the problem.
ArrayList<DrawCommands> path_color_stroke_list = new ArrayList<DrawCommands>();
ArrayList<DrawCommands> path_color_stroke_list_undone = new ArrayList<DrawCommands>();
ArrayList<BlurCommands> path_blur_list = new ArrayList<BlurCommands>();
ArrayList<BlurCommands> path_blur_list_undone = new ArrayList<BlurCommands>();
ArrayList<EditTextDrawCommands> editTextList = new ArrayList<EditTextDrawCommands>();
private Bitmap mBitmap;
private Paint transparentPaint;
private Paint mPaint;
public DrawingPanel(Context context, String imageStorageDir) {
super(context);
appContext = context;
setFocusable(true);
setFocusableInTouchMode(true);
setClickable(true);
this.setOnTouchListener(this);
mPath = new Path();
setDefaultPaintAttributes();
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 8;
blurRefImage = BitmapFactory.decodeResource(getResources(), R.drawable.canvas_test, bmOptions);
canvasBackImage = BitmapFactory.decodeResource(getResources(), R.drawable.canvas_test);
//stretch this small image to the size of the device so that it will be stretched and will already be blurred
blurRefImage = Bitmap.createScaledBitmap(blurRefImage, Utilities.getDeviceWidth(), Utilities.getDeviceHeight(), true);
blurRefImage = BlurBuilder.blurFullImage(appContext, blurRefImage, 20);
mBitmap = Bitmap.createBitmap(Utilities.getDeviceWidth(), Utilities.getDeviceHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
protected void setDefaultPaintAttributes() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(30);
//mPaint.setColor(0xcc000000);
transparentPaint = new Paint();
transparentPaint.setStyle(Paint.Style.STROKE);
transparentPaint.setStrokeJoin(Paint.Join.ROUND);
transparentPaint.setStrokeCap(Paint.Cap.ROUND);
transparentPaint.setStrokeWidth(60);
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
#Override
protected void onDraw(Canvas canvas) {
mCanvas.drawBitmap(canvasBackImage, 0, 0, mPaint);
//Draw Blur
for (BlurCommands path_blur : path_blur_list) {
mCanvas.drawPath(path_blur.getPath(), transparentPaint);
}
//Draw Paints
for (DrawCommands path_clr : path_color_stroke_list) {
mCanvas.drawPath(path_clr.getPath(), mPaint);
}
switch (CURRENT_MODE) {
case MODE_BLUR:
mCanvas.drawPath(mPath, transparentPaint);
break;
case MODE_PAINT:
mCanvas.drawPath(mPath, mPaint);
break;
}
canvas.drawBitmap(blurRefImage, 0, 0, mPaint);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
switch (CURRENT_MODE) {
case MODE_BLUR:
break;
case MODE_PAINT:
break;
default:
break;
}
}
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) {
switch (CURRENT_MODE) {
case MODE_BLUR:
case MODE_PAINT:
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
break;
default:
break;
}
}
}
private void touch_up(MotionEvent event) {
switch (CURRENT_MODE) {
case MODE_BLUR:
mPath.lineTo(mX, mY);
mPath = new Path();
path_blur_list.add(new BlurCommands(mPath, blurStrength, transparentPaint.getStrokeWidth()));
break;
case MODE_PAINT:
mPath.lineTo(mX, mY);
mPath = new Path();
path_color_stroke_list.add(new DrawCommands(mPath, mPaint.getColor(), mPaint.getStrokeWidth()));
Log.d(TAG, "Touch up: X: " + mX + " Y: " + mY);
break;
default:
break;
}
}
You probably want to switch the order of the 2 lines in touch_up that clear the path (new Path), and that add ad the path to the list (first add, then clear)
The error occurs because the mPath object is created matching the previous drawing mode since it was created on mouse-up with the previous drawing mode.
Move the mPath creation to touch_start and the current drawing mode will be used:
private void touch_start(float x, float y) {
mPath = new Path();
mPath.moveTo(x, y);
mX = x;
mY = y;
switch (CURRENT_MODE) {
case MODE_BLUR:
path_blur_list.add(new BlurCommands(mPath, blurStrength, transparentPaint.getStrokeWidth()));
break;
case MODE_PAINT:
path_color_stroke_list.add(new DrawCommands(mPath, mPaint.getColor(), mPaint.getStrokeWidth()));
break;
default:
break;
}
}
...
private void touch_up(MotionEvent event) {
mPath.lineTo(mX, mY);
}
Related
I'm letting the user to do painting in my app.The app will show some options on the screen once the whole screen is painted. And I want to check if the user has painted the whole screen.
Is there a way to detect if the user has painted the whole screen? Like an event triggered after the whole screen is painted.
Following is my code for painting:
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
Stack mXStack;
Stack mYStack;
public DrawingView(Context c) {
super(c);
context = c;
mPath = new Path();
mXStack = new Stack();
mYStack = new Stack();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(50f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawPath(circlePath, circlePaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.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) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(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;
}
}
Im making a basic app to test making paths.
So I got the paths to work, but when I am in the emulator and begin a path it starts the path about inch below from where I clicked.
Besides from the path being a inch off below, it will follow my mouse and make a path but always from a inch below where the mouse is.
This is my code:
public class Paths extends Activity {
Path newPath = new Path();
Paint paint = new Paint();
Canvas canvas = new Canvas();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_paths);
}
public boolean onTouchEvent(MotionEvent event) {
LinearLayout relative = (LinearLayout) findViewById(R.id.drawing_view2);
float x = event.getRawX();
float y = event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
newPath.moveTo(x, y);
relative.addView(new DrawView2(relative.getContext(), newPath));
return true;
case MotionEvent.ACTION_MOVE:
newPath.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
default:
return false;
}
relative.invalidate();
return true;
}
This is the java class that handles the paint and canvas objects.
private final Path path;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public DrawView2(Context context, Path path) {
super(context);
int mycolor = Color.parseColor("#6633CC");
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(mycolor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(8f);
this.path = path;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path, paint);
}
and my layout file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawing_view2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#33FF99"
You are getting coordinates with
float x = event.getRawX();
float y = event.getRawY();
Instead of this, try that:
float x = event.getX();
float y = event.getY();
I'm trying to draw on the my .png image, but it works very slow. If I'm drawing on the imageView without .png file it works fine. How can I solve this? As I understand I need to prevent "A LOT of drawings all the time", how can I realise this?
code:
public class Draw
extends Activity{
DrawingView dv ;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + "/MANUAL/workflow" + "/img.png");
int targetWidth = bm.getWidth() / 1;
int targetHeight = bm.getHeight() / 1;
Matrix matrix = new Matrix();
matrix.postScale(0.7f, 0.65f);
Bitmap size = Bitmap.createBitmap(bm, 0, 0, targetWidth, targetHeight, matrix, true);
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawBitmap(size, 0, 0, paint);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.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) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(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;
}
}
Your onDraw() method should look like this:
#Override
protected void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
canvas.drawBitmap(size, 0, 0, paint);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
All Bitmap decoding and resizing should be done outside (in the constructor or only when the view is resized), there is no need to decode and resize it every time when the result will be same every time.
i have try to draw a finger paint in android using Canvas. I have used the paint for Coloring the Current path.Remove and Appear the paths using undo redo option.But undo Redo works well. i use the Red color for Paint if i use the another color for drawing all the previous paths are changed to current color.
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class CustomView extends View implements OnTouchListener {
public Canvas mCanvas;
private Path mPath;
public Paint mPaint, mBitmapPaint;
Bitmap mBitmap;
Canvas canvas;
TabletActivity tabletActivity;
public ArrayList<Path> paths = new ArrayList<Path>();
public ArrayList<Path> undonePaths = new ArrayList<Path>();
private Bitmap im;
public CustomView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mCanvas = new Canvas();
mPath = new Path();
im = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_launcher);
DisplayMetrics metrics = getContext()
.getResources()
.getDisplayMetrics();
int w = metrics.widthPixels;
int h = metrics.heightPixels;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
// mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC))
// ;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// mPath = new Path();
// canvas.drawPath(mPath, mPaint);
// canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Path p : paths) {
canvas.drawPath(p, mPaint);
}
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
undonePaths.clear();
mPath.reset();
mPath.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) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
paths.add(mPath);
mPath = new Path();
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
}
// toast the user
}
public void onClickRedo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
} else {
}
// toast the user
}
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;
}
}
As user603125 says, currently you only have one paint object and you paint all paths with that paint. Remember that in onDraw you draw all paths anew every time.
To solve this, you'll have to keep track of the color to use by every path, e.g. in a map and do something like so:
private Map<Path, Color> mPathColors = new HashMap<Path, Color>(); // map for path colors
private Color mCurrentColor; // color to paint current path with (has to be set somewhere)
...
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Path p : paths) {
mPaint.setColor(mPathColors.get(p);
canvas.drawPath(p, mPaint);
}
mPaint.setColor(mCurrentColor);
canvas.drawPath(mPath, mPaint);
}
And in touch_up() write the current color to the map like so:
private void touch_up() {
...
paths.add(mPath);
mPathColors.put(mPath, mCurrentColor);
...
}
You are using the Same paint object to draw the previous and as well as the current path.
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
mPaint.setColor(Color.YELLOW);
for (Path p : paths) {
canvas.drawPath(p, mPaint);
}
mPaint.setColor(Color.RED);
canvas.drawPath(mPath, mPaint);
}
Good morning,
A portion of my apps features the ability to write down some hand written notes. I am using pieces from the fingerpaint example to implement the "eraser" in my app:
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
mPaint.setStrokeWidth(45);
mPaint.setStrokeCap(Paint.Cap.ROUND);
The problem is whenever I erase there is a black path where the user has erased. It is gone once the user picks up their finger, but it is there while they are erasing. My friend tells me that PorterDuff modes are not supposed to be used in real time, but I don't believe him. Here's some more of my code just in case I did something dumb:
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(false);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.BUTT);
mPaint.setStrokeWidth(6);
mBitmap = Bitmap.createBitmap(800, 480,Bitmap.Config.ARGB_8888);
bBitmap = Bitmap.createBitmap(800, 480,Bitmap.Config.ARGB_8888);
bBitmap.eraseColor(Color.WHITE);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint();
maxX = maxY = 100;
minX = 750;
minY = 400;
//
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
//
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bBitmap, 0, 0, null);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
Is it possible to do what I want this eraser to do? Is there a better way to do this? Is my friend actually right?
Also I tried just painting white as an erase but it's not going to work because sometimes there is an image underneath that the user is marking up. I could go through and make every white pixel transparent, but that seems super inefficient.
I have found a way to do this properly, it does the erasing with your finger, without the black stroke.
Here is my solution :
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(isEraseMode()){
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
if(isEraseMode()){
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
mPath.moveTo(x, y);
}
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
Ok so I figured out a solution. I'll leave this here for people running into a similar problem:
case MotionEvent.ACTION_DOWN:
mPaint.setStrokeWidth(25);
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
mCanvas.drawCircle(x, y, 10, mPaint);
isErase = true;
invalidate();
}
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
if(isErase)
{
mCanvas.drawCircle(x, y, 20, mPaint);
}
else{
touch_move(x, y);
}invalidate();
break;
I have the same question.
finally, I figured out the solution.
don't use the canvas passed from onDraw(),use the mCanvas created in constructor instead.
(Workaround) it will cost you opasity.
after initialising the canvas, maybe in onCreate of your activity.
myCanvasView.setAlpha(0.99f);
I agree with #Rovers, just change the canvas in this way:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
if (!erase) {
canvas.drawPath(drawPath, drawPaint);
} else {
drawCanvas.drawPath(drawPath, drawPaint);
}
}
There are two kind of canvas into onDraw method --> drawCanvas and canvas.