MOBILE

Android Application Development : Rolling Your Own Widgets (part 2) - Canvas Drawing

11/19/2013 8:07:56 PM

2. Canvas Drawing

Now that we’ve explored how widgets allocate the space on the screen in which they draw themselves, we can turn to coding some widgets that actually do some drawing.

The Android framework handles drawing in a way that should be familiar, now that you’ve read about measurement and arrangement. When some part of the application determines that the current screen drawing is stale because some state has changed, it calls the View method invalidate. This call causes a redraw event to be added to the event queue.

Eventually, when that event is processed, the framework calls the draw method at the top of the view tree. This time the call is propagated preorder, with each view drawing itself before it calls its children. This means that leaf views are drawn after their parents, which are, in turn, drawn after their parents. Views that are lower in the tree appear to be drawn on top of those nearer the root of the tree.

The draw method calls onDraw, which a subclass overrides to implement its custom rendering. When your widget’s onDraw method is called, it must render itself according to the current application state and return. It turns out, by the way, that neither View.draw nor ViewGroup.dispatchDraw (responsible for the traversal of the view tree) is final! Override them at your peril!

In order to prevent extra painting, the framework maintains some state information about the view, called the clip rectangle. A key concept in the UI framework, the clip rectangle is part of the state passed in calls to a component’s graphical rendering methods. It has a location and size that can be retrieved and adjusted through methods on the Canvas, and it acts like a stencil through which a component does all of its drawing. By correctly setting the size, shape, and location of the clip rectangle aperture, the framework can prevent a component from drawing outside its boundaries or redrawing regions that are already correctly drawn.

Before proceeding to the specifics of drawing, let’s again put the discussion in the context of Android’s single-threaded MVC design pattern. There are two essential rules:

  • Drawing code should be inside the onDraw method. Your widget should draw itself completely, reflecting the program’s current state, when onDraw is invoked.

  • A widget should draw itself as quickly as possible when onDraw is invoked. The middle of the call to onDraw is no time to run a complex database query or to determine the status of some distant networked service. All the state you need to draw should be cached and ready for use at drawing time.

The Android UI framework uses four main classes in drawing. If you are going to implement custom widgets and do your own drawing, you will want to become very familiar with them:


Canvas (a subclass of android.graphics.Canvas)

The canvas has no complete analog in real-life materials. You might think of it as a complex easel that can orient, bend, and even crumple the paper on which you are drawing in interesting ways. It maintains the clip rectangle, the stencil through which you paint. It can also scale drawings as they are drawn, like a photographic enlarger. It can even perform other transformations for which material analogs are more difficult to find: mapping colors and drawing text along paths.


Paint (a subclass of android.graphics.Paint)

This is the medium with which you will draw. It controls the color, transparency, and brush size for objects painted on the canvas. It also controls font, size, and style when drawing text.


Bitmap (a subclass of android.graphics.Bitmap)

This is the paper you are drawing on. It holds the actual pixels that you draw.


Drawables (likely a subclass of android.graphics.drawable.Drawable)

This is the thing you want to draw: a rectangle or image. Although not all of the things that you draw are Drawables (text, for instance, is not), many, especially the more complex ones, are.

Example 1 used only the Canvas, passed as a parameter to onDraw, to do its drawing. In order to do anything more interesting, we will need Paint, at the very least. Paint provides control over the color and transparency (alpha) of the graphics drawn with it. Paint has many, many other capabilities, some of which are described in Section 2. Example 2, however, is enough to get you started. Explore the class documentation for other useful attributes.

The graphic created by the code in the example is shown in Figure 1.

Example 2. Using Paint
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);

Paint paint = new Paint();

canvas.drawLine(33, 0, 33, 100, paint);

paint.setColor(Color.RED);
paint.setStrokeWidth(10);
canvas.drawLine(56, 0, 56, 100, paint);

paint.setColor(Color.GREEN);
paint.setStrokeWidth(5);

for (int y = 30, alpha = 255; alpha > 2; alpha >>= 1, y += 10) {
paint.setAlpha(alpha);
canvas.drawLine(0, y, 100, y, paint);
}
}
Figure 1. Using Paint


With the addition of Paint, we are prepared to understand most of the other tools necessary to create a useful widget. Example 3. While still not very complex, it demonstrates all the pieces of a fully functional widget. It handles layout and highlighting, and reflects the state of the model to which it is attached.

Example 3. Dot widget
package com.oreilly.android.intro.view;

import android.content.Context;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;

import android.view.View;

import com.oreilly.android.intro.model.Dot;
import com.oreilly.android.intro.model.Dots;


public class DotView extends View {
private final Dots dots;

/**
* @param context the rest of the application
* @param dots the dots we draw
*/
public DotView(Context context, Dots dots) {
super(context);
this.dots = dots;
setMinimumWidth(180);
setMinimumHeight(200);
setFocusable(true);
}

/** @see android.view.View#onMeasure(int, int) */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getSuggestedMinimumWidth(),
getSuggestedMinimumHeight());
}

/** @see android.view.View#onDraw(android.graphics.Canvas) */
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);

Paint paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setColor(hasFocus() ? Color.BLUE : Color.GRAY);
canvas.drawRect(0, 0, getWidth() - 1, getHeight() -1, paint);

paint.setStyle(Style.FILL);
for (Dot dot : dots.getDots()) {
paint.setColor(dot.getColor());
canvas.drawCircle(
dot.getX(),
dot.getY(),
dot.getDiameter(),
paint);
}
}
}

As with Paint, we have only enough space to begin an exploration of Canvas methods. There are two groups of functionality, however, that are worth special notice.

Other  
  •  iPhone SDK 3 Programming : XML Processing - An RSS Reader Application
  •  iPhone SDK 3 Programming : XML Processing - Simple API for XML (SAX)
  •  iPhone SDK 3 Programming : XML Processing - Document Object Model (DOM)
  •  iPhone SDK 3 Programming : XML and RSS
  •  Windows Phone 8 : Making Money - Modifying Your Application, Dealing with Failed Submissions, Using Ads in Your Apps
  •  Windows Phone 8 : Making Money - Submitting Your App (part 3) - After the Submission
  •  Windows Phone 8 : Making Money - Submitting Your App (part 2) - The Submission Process
  •  Windows Phone 8 : Making Money - Submitting Your App (part 1) - Preparing Your Application
  •  Windows Phone 8 : Making Money - What Is the Store?
  •  BlackBerry Push APIs (part 3) - Building an Application that Uses the BlackBerry Push APIs - Checking the Status of a Push Request and Cancelling a Push Request
  •  
    Top 10
    Review : Sigma 24mm f/1.4 DG HSM Art
    Review : Canon EF11-24mm f/4L USM
    Review : Creative Sound Blaster Roar 2
    Review : Philips Fidelio M2L
    Review : Alienware 17 - Dell's Alienware laptops
    Review Smartwatch : Wellograph
    Review : Xiaomi Redmi 2
    Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
    Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
    3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    VIDEO TUTORIAL
    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
    Popular Tags
    Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8