2013-08-26

In this series, we will create a finger-painting app for Android using touch interaction. The user will be able to select from a color palette, choose a brush size, erase, create a new drawing, or save their existing drawing to the device gallery.

Series Format

This series on Creating a Drawing App will be in three parts:

Interface Creation

Touch Interaction

Essential Functionality

In the first part of the series we created the user interface. In the second part we implemented drawing on the canvas and choosing colors. In this the final part of the series we will introduce the ability to erase, to create new drawings, and to save a drawing to the gallery on the user device. We will look at the options you can use to enhance this app in future tutorials, including pattern fills and opacity.

Final Preview

1. Choosing Brush Sizes

Step 1

Last time we implemented drawing on the canvas, now we can let the user choose a brush size. The brush size options will appear when the user presses the brush button we added to the interface. To respond to this, extend the opening line of your main Activity class declaration to implement the OnClickListener interface:

You will need the following import statements added to the class for this tutorial:

Add the following instance variables to the class to store the three dimension values we defined last time:

Instantiate them in onCreate:

We will use these later. You should already have an ImageButton instance variable in the main class named “currPaint” – extend that line to add another now for the drawing button:

In onCreate retrieve a reference to the button from the layout:

Set the class up as a click listener for the button:

Step 2

Add an onClick method to the class:

Inside the method, check for clicks on the drawing button:

We will be adding conditional blocks to the onClick method for the other buttons later.

Step 3

When the user clicks the button, we will display a dialog presenting them with the three button sizes. Inside the if block, create a Dialog and set the title:

Let’s define the Dialog layout in XML – add a new file in your app’s “res/layout” folder, naming it “brush_chooser.xml” and entering the following outline:

Inside the Linear Layout, add a button for each size:

Each button has an ID for identification in the Activity Java code. You will notice that each one also has a content description attribute – add the specified strings to your “res/values” strings XML file:

As you can see in the layout file, each button also has a drawable file listed as its source attribute. Create new files for each of these in your “res/drawables” folder(s) now, starting with “small.xml” and entering the following content:

Notice that we use the dimension values we defined. Next add “medium.xml” to the drawables folder, entering the following shape:

Finally add “large.xml” with the following content:

Back in your main Activity class onClick method, after creating the Dialog and setting its title, you can now set the layout:

Step 4

Before we continue with the Dialog, let’s alter the custom drawing View class to use different brush sizes. In your DrawingView class, add the following import statements for this tutorial:

Add two instance variables to the class:

We will use the first variable for the brush size and the second to keep track of the last brush size used when the user switches to the eraser, so that we can revert back to the correct size when they decide to switch back to drawing. In the setupDrawing method, before the code already in there, add the following to instantiate these variables:

We use the dimension value for the medium sized brush to begin with. You can now update the line in the method where you set the stroke width with a hard-coded value to use this variable value instead:

Add the following method to the class to set the brush size:

Inside the method, update the brush size with the passed value:

We will be passing the value from the dimensions file when we call this method, so we have to calculate its dimension value. We update the variable and the Paint object to use the new size. Now add methods to get and set the other size variable we created:

We will call these methods from the main Activity class.

Step 5

Back in your main Activity class, let’s complete the Dialog code in the onClick method. After setting the content view on the Dialog object, listen for clicks on the three size buttons, starting with the small one:

We set the size using the methods we added to the custom View class as soon as the user clicks a brush size button, then immediately dismiss the Dialog. Next do the same for the medium and large buttons:

Complete the draw button section of onClick by displaying the Dialog:

The Dialog will display until the user makes a selection or goes back to the Activity.

Step 6

Use the new method to set the initial brush size in onCreate:

2. Erasing

Step 1

Now let’s add erasing to the app. In the custom drawing View class, add a boolean instance variable to act as a flag for whether the user is currently erasing or not:

Initially we will assume that the user is drawing, not erasing. Add the following method to the class:

Inside the method, first update the flag variable:

Now alter the Paint object to erase or switch back to drawing:

If you’re looking for an advanced topic to explore, have a look at the PorterDuff.Mode options.

Step 2

Back in the main Activity class, add another ImageButton to the list of instance variables:

In onCreate, retrieve a reference to the button and set the class up to listen for clicks:

Add a conditional statement for the button in onClick after the conditional for the draw button:

As with the draw button, we will let the user choose an eraser size from a Dialog. Inside the conditional block for the erase button, create and prepare the Dialog as before:

We use the same layout as the draw button Dialog. Setup click listeners for the size buttons as before, this time calling the new erase method we added to the View class:

We call the method to set the brush size as with the draw button, this time first setting the erase flag to true. Finally, display the Dialog:

The user will be able to erase using touch interaction as with drawing:

Step 3

When the user clicks the draw button and chooses a brush size, we need to set back to drawing in case they have previously been erasing. In the three click listeners you added for the small, medium and large buttons in the draw button section of onClick, call the erase method with a false parameter – add this in each onClick before calling dismiss on the “brushDialog” object:

When the user has been erasing and clicks a paint color button, we will assume that they want to switch back to drawing. In the paintClicked method, before the existing code, call the erase method, passing false:

Still inside paintClicked, set the brush size back to the last one used when drawing rather than erasing:

This type of processing is motivated by assumptions about what the user wants to do based on their actions – you could potentially enhance this app along these lines, so bear that in mind if you want to carry on working on the app later.

3. New Drawings

Step 1

We added a button for the user to start a new drawing, so let’s implement that now. Add another to the list of ImageButton instance variables in your main Activity class:

Instantiate it with a reference to the button listed in the layout, in onCreate, also listening for clicks:

Step 2

In onClick, add another conditional block for the new button:

In your custom drawing View class, add a method to start a new drawing:

The method simply clears the canvas and updates the display.

Back in the main Activity class conditional block for the new button in onCreate, let’s verify that the user definitely wants to start a new drawing:

The Dialog lets the user change their mind, calling the new method if they decide to go ahead and start a new drawing, in which case the current drawing is cleared.

4. Save Drawings

Step 1

The one remaining part of the app functionality is the ability to save drawings to the device. Add the save button as the last in the sequence of ImageButton instance variables in the main Activity class:

Instantiate it and listen for clicks in onCreate:

Add a conditional for it in onClick:

Let’s use a similar algorithm to the one we used for creating new drawings, to check that the user wants to go ahead and save:

If the user chooses to go ahead and save, we need to output the currently displayed View as an image. In the onClick method for the save Dialog, start by enabling the drawing cache on the custom View:

Now attempt to write the image to a file:

Take a moment to look over this code. We use the insertImage method to attempt to write the image to the media store for images on the device, which should save it to the user gallery. We pass the content resolver, drawing cache for the displayed View, a randomly generated UUID string for the filename with PNG extension and a short description. The method returns the URL of the image created, or null if the operation was unsuccessful – this lets us give user feedback:

Finally, destroy the drawing cache so that any future drawings saved won’t use the existing cache:

On browsing to the device gallery, the user should now be able to see their drawing image:

Conclusion

This tutorial completes the functionality for our basic drawing app! When you run the app you should be able to draw, choose colors, choose brush and eraser sizes, start new drawings and save drawings to the gallery. We have worked through the basic process of facilitating drawing using touchscreen interaction on Android, but there are many ways in which you could enhance the application so try experimenting with it to build in your own additional functionality. In future tutorials we will cover using pattern fills rather than simply drawing with solid colors, using opacity, and letting the user choose an opacity level. We will also cover drawing on Android devices where the interaction model is not a touchscreen, for example with a mouse or trackball.

Show more