Exploring Android Canvas Drawing— For Shapes, Bitmaps andCustom views.

Mayuri Khinvasara
AndroidPub
Published in
6 min readJan 9, 2019

--

Would you like to

  1. Create your own drawing (UI) on the screen OR create custom views ?
  2. Modify existing views and customize their look and feel ?
  3. Draw any shape, view or just bitmaps ?
  4. Create something which isn’t already available ?

The power of Android for free hand drawing on pen and paper !

Android Canvas gives you exactly that. Just dive in and create your own magic.

If you know the basics and directly want to view the code, find the entire source code here on GitHub.

So what exactly is Android Canvas ?

The Android framework APIs provides a set of 2D drawing APIs that allow you to render your own custom graphics onto a canvas or to modify existing Views to customize their look and feel. Basically, Canvas is a class in Android that performs 2D drawing onto the screen of different objects.

Your mobile screen is your canvas

Just consider you mobile screen as a blank paper and draw on it. You need to define anchor points and shapes so as to draw on the screen. Remember the school level graphs ? Something very similar.

Define X & Y coordinates and the shape you want.

Create your own custom view class

Just create custom view class. Since you want to draw your own UI , extend View class to get the lifecycle of the basic view hierarchy.

public class CustomView extends View {

public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}

Define a paint object with default colors and styling

// defines paint and canvas
private Paint drawPaint;

// Setup paint with color and stroke styles
private void setupPaint() {
drawPaint = new Paint();
drawPaint.setColor(Color.BLUE);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5);
drawPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}

Create and initialise the paint object in your constructor only. Most of the times, our basic settings don’t change. We can then use this paint object every where else in the code and only change properties we want.

public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);

setupPaint();
}

The magic methods : onDraw() and invalidate()

All of canvas drawing will happen in onDraw method. Whenever you want to draw any custom objects , you set the paint styling, call default draw.. API methods. All these internally call onDraw.

Get your canvas instance in onDraw and save it for drawing.

private Canvas canvas;@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;

Every time, you draw something new on the canvas , you need to refresh it. Your entire canvas is re-drawn. And hence you need to perform minimal operations in onDraw().

To tell the view, that is has to refresh use invalidate() method.

canvas.invalidate();

Remember our paint object is initialised in constructor so that we don’t create it again and again on draw. OnDraw gets called every single time you want to change anything on the UI. So it’s an expensive call. We don’t want to do anything extra than required on onDraw method.

Drawing basics

A variety of basic draw API’s are available on the canvas object. We can use these basic API;s to create our own custom shapes and figures. some common ones are :

Draw Line

You define the two points with their x, y coordinates and draw path between them.

Path path = new Path();
path.moveTo(x1, y1);
path.lineTo(x2, y2);
path.close();
canvas.drawPath(path, drawPaint);

Draw Circle

The simplest shape. You just need to specify the x coordinate, y coordinate on the screen and the radius. Also set any paint color if you want.

canvas.drawCircle(xCordinate, yCordinate, RADIUS, drawPaint);

Draw Rectangle

Create a rectangle with x, y, height, width.

public void drawRectangle(int x, int y) {
drawPaint.setColor(Color.RED);
Rect rectangle = new Rect((int) (x - ((0.8) * RADIUS)), (int) (y - ((0.6) * RADIUS)), (int) (x + ((0.8) * RADIUS)), (int) (y + ((0.6 * RADIUS)))); canvas.drawRect(rectangle, drawPaint);
}

Draw Square

Create a rectangle object, with the required coordinates, with the same width and height.

double squareSideHalf = 1 / Math.sqrt(2);
//Consider pivot x,y as centroid.

public void drawRectangle(int x, int y) {
drawPaint.setColor(Color.RED);
Rect rectangle = new Rect((int) (x - (squareSideHalf * RADIUS)), (int) (y - (squareSideHalf * RADIUS)), (int) (x + (squareSideHalf * RADIUS)), (int) (y + ((squareSideHalf * RADIUS))));
canvas.drawRect(rectangle, drawPaint);
}

Getting tougher : Draw Triangle ()

Triangle is basically three vertices connected with a line. You need to find those three vertices and draw a line between them.

Below we draw an equilateral triangle

/*
Select three vertices of triangle. Draw 3 lines between them to form a triangle
*/
public void drawTriangle(int x, int y, int width) {
drawPaint.setColor(Color.GREEN);
int halfWidth = width / 2;

Path path = new Path();
path.moveTo(x, y - halfWidth); // Top
path.lineTo(x - halfWidth, y + halfWidth); // Bottom left
path.lineTo(x + halfWidth, y + halfWidth); // Bottom right
path.lineTo(x, y - halfWidth); // Back to Top
path.close();
canvas.drawPath(path, drawPaint);
}

Update Canvas

If you follow the MVP / MVVM / etc other architectural pattern, you might want to refresh your canvas from other layers. Just get the canvas object , do all your business logic for drawing, and then run invalidate.

private void upDateCanvas(Shape shape) {
//your business logic for shapes creation etc here
canvas.invalidate();
}

View or SurfaceView ?

If you want to know more about multi-threading

[Use View : If your application does not require a significant amount of processing or frame-rate speed (perhaps for a chess game, a snake game, or another slowly-animated application). In the same thread as your UI Activity, wherein you create a custom View component in your layout, call invalidate() and then handle the onDraw() callback.

Use SurfaceView — If you have high computation or so the application doesn’t to wait until the system’s View hierarchy is ready to draw and want to run in a separate thread, wherein you manage a SurfaceView and perform draws to the Canvas as fast as your thread is capable (you do not need to request invalidate())]

Sample code :

You can deep dive into the code here on GitHub and check out details there.

Draw different shapes on canvas. Full source code available here on github

In the next article, we will learn more on handling touch events on Canvas like touch, click, long press, etc.

Thats’ it. Thank you for reading. Please let me know what you liked in the article and what would you like to know more.

Full source code available here on GitHub

If you liked the article, show some love by clicking on the 👏 button . It will motivate me to write more articles like this. Please share any feedback or tweet about it here. Read my other blog posts here :

Happy Coding ! :)

--

--

Mayuri Khinvasara
AndroidPub

Android Developer 💙 | Learner, Speaker and Writer | Leading GDG & Women Techmakers Pune | Passionate about technology, community | Curious Student for life !