First of all we have to speak about the Android Canvas. With Canvas we can perform 2D drawing onto the screen. Basically it is an empty space to draw onto.
The Canvas class is not a new concept, this class is actually wrapping a SKCanvas under the hood. The SKCanvas comes from SKIA, which is a 2D Graphics Library that is used on many different platforms. SKIA is used on platforms such as Google Chrome, Firefox OS, Flutter, Fuschia etc. Once you understand how the Canvas works on Android, the same drawing concepts apply to many other different platforms.
Shapes to draw on Canvas
There are many different things you can draw onto a Canvas. One of the most common drawing operations is to draw a bitmap (image), a line, a circle, arc or recangle.
On our tutorial we will use the drawArc, drawCircle and drawLine.
There are two Canvas.drawArc method implementations, but we will use the simpler method which has 5 arguments.
- oval: RectF – According to the docs, this parameter represents “the bounds of oval used to define the shape and size of the arc”. This is important because it helps to remind us that when we are drawing an arc, we are really drawing a section of an oval.
- startAngle: float – Now we are getting into the land of confusion. The docs define this parameter as the “starting angle (in degrees) where the arc begins”. If you’re asking yourself, “starting from what!?” then you are a mind reader and have accurately guessed exactly what I thought when reading that. But before I help answer your woes, let’s continue with the other parameters.
- sweepAngle: float – Another parameter with the word “angle” in it! Not a great start. The docs define this parameter as the “sweep angle (in degrees) measured clockwise”. At this point if you’re like me you’re probably wondering “what on earth is a sweep angle”. But don’t worry, all shall soon be revealed.
- useCenter: boolean – Now this one, surprisingly, has a super helpful description! According to the docs, “if true, include the center of the oval in the arc, and close it if it is being stroked. This will draw a wedge.” Finally! A visual clue for a visual method!
- paint: Paint – And lastly, the Paint object used to draw our arc.
draw an arc
It draws a simple circle. It only requires the center coordinate and the radius.
draw an circle
With drawLine we can draw on the canvas a simple line. For this we need just two points on our canvas. One for the start and one for the end point.
draw a line
After a short prologue, we can start coding 🙂
Step 1 – activity_main.xml
In the first step we will create our user interface. It will be again very simple. It will contain our LampView and a Button, what will turn on an off our lamp.
We will align the Views on our screen with ConstarintLayout.
Our LampView has a “state” argument with the value “_off”. This will be responsible of the state of the lamp. With the button we will change this state. The implenetation cames later.
Step 2 – LampView::class
To have our custom view, we have to extend the LampView::class with the View class.
This class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.).
After the extend our LampView::class, we have to implement the onDraw method. This method will run at the first time, so we will implement here the methods separetly and draw the shapes on the canvas.
Measure the view and its content to determine the measured width and the measured height. This method is invoked by measure(int, int). When overriding this method, we must call setMeasuredDimension(int, int) to store the measured width and height of this view.
We will draw in this method the border of the bulb. As we talked about it earlier, we will use drawArc.
In the next method we have to specify the start and the end point of the lines from the arc of the bulb. For this we will call on the help of mathematics 😉 We will have here some cosine calculations.
Next phase of our drawing is to draw the socket of the lamp. It will draw 5 lines, the left and the right lines and the 3 lines in the middle.
The final step is to fill the socket with color. To do this the area must be defined. We will identify there two areas. A rectangle and at the bottom of it a trapeze.
Save the state
As we navigate through, out of, and back to our app, the View instances in our app transition through different states in thier lifecycle.
onSaveInstanceState is called to retrieve per-instance state from a view before being killed so that the state can be restored in onCreate(Bundle) or onRestoreInstanceState(Bundle).
In the onSaveInstanceState we will save the state of the LampView and when we rotate our device or send it to the background, then the lamp will have the same state.
After the introduction here is the whole source code for the LampView.
Step 2 – Creating Custom XML Attributes
As we talked earlier, we will have the “state” attribute, which can set the state of our app. If the “state” has the value “_on” then the lamp is turned on, if it is “_off”, then our lamp is off.
To create a new XML attribute go to res/values and create new values resource file named attrs.xml.
Add the following lines to the file.
Step 3 – MainActivity::class
The last step in our LampViewApp is the veeery simple MainActivity::class.
In the MainActivity::class we have only the setOnClickListener of our btn_setState Button. Whit it we can set the state of the lamp, and we will do it with a simple if-else statement.
- Rebecca Franks: Getting Started with Android Canvas Drawing
- Amanda Hill: Android Canvas’ drawArc Method: A Visual Guide
- Elye: Learn All Android Canvas Draw Functions
- Ahmed Tarek: Android Custom View Tutorial
- View – Official Android developer documentation
I hope the description was understandable and clear. But if you have still questions, then leave me comments below! 😉
Have a nice a day! 🙂