Click here to Skip to main content
15,036,145 members
Articles / Mobile Apps / Android
Technical Blog
Posted 31 Oct 2015

Tagged as

Stats

31K views
8 bookmarked

Android Drawing App Tutorial – Pt. 1

Rate me:
Please Sign up or sign in to vote.
4.20/5 (3 votes)
31 Oct 2015CPOL11 min read
In this blog post, I will show you how to create Android drawing app. This blog post is part one of a two part tutorial series where I will show you how to create simple but delightful Android drawing app.

In this blog post, I will show you how to create Android drawing app. This blog post is part one of a two part tutorial series where I will show you how to create simple but delightful Android drawing app.  As the name indicates this drawing app will enable users to draw or sketch on their Android devices using their fingers.  The core features of this app will include:

  1. Draw – Users will be able to draw on a blank canvas (whiteboard) .
  2. Erase – Users will be able to erase what has been drawn.
  3. Undo – Users will be able to undo and redo drawing paths.
  4. Color – Users will be able to draw using a color of their choice from at least these colors: black, dark gray, light gray, blue, red, and green, orange, yellow .
  5. Share – Users will be able to capture a screen shot and email it to a friend.

”Create

Step 4: Test the View – You can now run your app to test the View. As you can expect, it will be a blank screen like the one below. However the good thing is that it did not give any error. We will now proceed to implement the use cases for this app which are draw, erase, undo, share and choose color.

Implement Drawing

Much of Android development consists of responding to events. You write code that will be executed when a particular event occurs. The system notifies you that this event has occurred through life-cycle events and listeners. To draw something on the screen, you have to respond to or override one of such events – the onDraw() event which is where every view draws itself.

In the onDraw() method you are passed the Canvas for the view that you have sub-classed, and what is a Canvas you may ask. Good thing that you asked because Canvas is one of the three components that you must understand to effectively create an Android drawing app. The other two are the Paint and the Path. So let us examine this core components, first the official definition of the Canvas.

The Canvas class holds the “draw” calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).

http://developer.android.com/reference/android/graphics/Canvas.html

canvas example

  1. Canvas – as the name implies, the Canvas is what you draw upon. It is the drawing surface for what you are drawing and it knows how to transfer that drawing to the actual View.  The Canvas is your convenient middle man that abstracts away  the nuances of writing directly to the underlying view. The Android developer guide calls it an “interface” which pretends to be “the actual surface upon which your graphics will be drawn” while in reality , it holds all of your “draw” calls and then places them into the window for you. The TwoToasters development team gave a good description of a Canvas and the other two core components in this blog post.
  2. Paint – after you obtain the surface to draw upon – the Canvas, you also need something to draw with – the Paint. As the name implies the Paint object “holds the style and color information”. It defines the “color, style, font, and so forth of each shape you draw”.
  3. Path  – now that you have the surface to draw upon and the drawing object to use to draw upon that, you need to decide what direction that you want to draw. Do you want to go up, down, left or right. This direction is know as the Path as in a path. It provides “geometric paths consisting of straight line segments, quadratic curves, and cubic curves.” To help you better understand the concept of Path, remember that at the beginning of this post I mentioned that we will implement “Undo” which is a common feature in most drawing apps. The way we will implement it is to keep a history of every path we draw, which is anytime we go from point A to point B. So if the user want to “Undo” their last drawing all we have to do is to remove the last entry in our list of Paths, wipe the screen clean and then re-draw everything again in that list except this time we will not re-draw that Path which have been removed. This happens at a blazing speed giving the user the illusion that we just erased the last thing they draw.

Let us now proceed to apply the concepts we learned above to our drawing. Before we start drawing, it is recommended by the Android developer guide to create the objects that you will need for drawing ahead of time. Because creating them within the onDraw() method will degrade your app performance.

Step 1 – Add Required Components – at the top of your CustomView.java class, declare the following instance variables to represent the different components we will use for this app. I have added comments to convey what each object is used for.

//drawing path
    private Path drawPath;

    //defines what to draw
    private Paint canvasPaint;

    //defines how to draw
    private Paint drawPaint;

    //initial color
    private int paintColor = 0xFF660000;

    //canvas - holding pen, holds your drawings
    //and transfers them to the view
    private Canvas drawCanvas;

    //canvas bitmap
    private Bitmap canvasBitmap;

    //brush size
    private float currentBrushSize, lastBrushSize;

Step 2 – Initialize Variables – initializing graphic objects is an expensive computational  task so it is recommended that we do that before we start drawing and the best place to initialize our components is in the constructor. However instead of cluttering the constructor we can create a private method called init(). Go ahead and add the init() method to your CustomView.java class and below is the content of that  method for now.

private void init(){
        currentBrushSize = getResources().getInteger(R.integer.medium_size);
        lastBrushSize = currentBrushSize;

        drawPath = new Path();
        drawPaint = new Paint();
        drawPaint.setColor(paintColor);
        drawPaint.setAntiAlias(true);
        drawPaint.setStrokeWidth(currentBrushSize);
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);

        canvasPaint = new Paint(Paint.DITHER_FLAG);

    }

Step 3 – Update Constructor – with the init method in place, we can now call it from the constructor like this

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

Step 4 – Override onDraw – drawing for all View objects happens in the onDraw(), if we had sub-classed a View sub-class like the Button for instance, then our Custom View will in the minimum know how to draw itself as a button. Since we sub classed the view directly we have to tell our Custom View how to draw itself via the onDraw(). Update your onDraw() method with the code below.

@Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(canvasBitmap, 0 , 0, canvasPaint);
        canvas.drawPath(drawPath, drawPaint);
    }

Step 5: Implement OnSizeChanged – this method is called during layout when the size of this view has changed. During creation the size of our view starts at 0 until the view rendering engine finishes calculating the size of your screen then it will call this method to update the size. Remember that when we added this view to our layout we declared the width and height of it to be match parent, well the height and width of that parent has to be calculated and the size of the view will adjust accordingly. You can essentially consider this method as part of the initialization routines of the view and it is inside this method that we initialize our bitmap and canvas object, if you don’t a Null Exception will be thrown when you try to use those objects in your onDraw method. Add this method below to your CustomView.java class file.

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
       //create canvas of certain device size.
        super.onSizeChanged(w, h, oldw, oldh);

        //create Bitmap of certain w,h
        canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

        //apply bitmap to graphic to start drawing.
        drawCanvas = new Canvas(canvasBitmap);
    }

Step 6: Implement Touch Listener – at this point our custom view can draw something if we call it programmatically with the appropriate X and Y coordinates, however I suspect that you did not want to create an Android drawing app that can only be told to draw through code.  The users of your app will want to move their finger on the screen and see something draw, in other for that to happen you have to register touch events as drawing actions. Your CustomView class has an onTouchEvent() method that you can override to accomplish this. Here is the code that accomplishes this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    float touchX = event.getX();
    float touchY = event.getY();
    //respond to down, move and up events
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            drawPath.moveTo(touchX, touchY);
            break;
        case MotionEvent.ACTION_MOVE:
            drawPath.lineTo(touchX, touchY);
            break;
        case MotionEvent.ACTION_UP:
            drawPath.lineTo(touchX, touchY);
            drawCanvas.drawPath(drawPath, drawPaint);
            drawPath.reset();
            break;
        default:
            return false;
    }
    //redraw
    invalidate();
    return true;
}

Here is what was going on in the above code:

  1. We are passed an object of type MotionEvent
  2. Using this MotionEvent we get the X and Y coordinates of where the touch occurred in the screen.  We store these coordinates in touchX and Y variables
  3. We then run a switch statement on the event.getAction() method which return a result of an int.
  4. If this action evaluates to a ACTION_DOWN constant of the MotionEvent class, we know that the user just touched the screen so we move to that point.
  5. If the int action evaluates to ACTION_MOVE, then we know that the user intents to draw, and we use our Path object to draw a line from point X to point Y
  6. If the action avaluates to ACTION_UP, then we know that the user is done, so time to transfer the drawing from the surface (Canvas) which we are drawing upon to the actual screen. And then we reset the Path object (drawPath) so that we can start afresh next time the screen is touched.
  7. When we are done, we have to notify the view that the content of what it is currently displaying has changed by calling invalidate(), this will call the onDraw() method and the screen will be repainted.

Go ahead and give it a try at this point, you should be able to draw to the screen using your finger or any other input.

Implement Erase Drawing

There are two ways we can  implement erasing our drawing: we can wipe off everything in the screen and start afresh or we can manually erase our drawing line by line. When we erase everything in the screen at once, what we are doing is essentially starting afresh and when we erase our drawing manually what we are doing in a nutshell is painting white color over our existing drawing to give it a resemblance of being “erased” .

There are three steps in implementing either types of our erase and for that matter any of the other operations that we want to implement such as undo, save, etc. First we have to create a method that accomplishes each use case, then we add an icon or button or something that the user will have to click to signal the action that they want to perform, then we attach a listener to each button and when clicked we call the appropriate method.

We will place all of our drawing related icons in a bottom toolbar. Our new project template already have a top toolbar, now we want to add another toolbar to the bottom and then we will add the icons to it.

Add Button Toolbar

Follow the steps below to add another material design toolbar to the bottom of your app.

Step 1: Update Your Layout – currently your content_main.xml contains only your custom view, well we need to change that a bit to accommodate our bottom toolbar. So go ahead and update your content_main.xml to now use a RelativeLayout as the root layout with two child views. Remember to use your package name, here it the update layout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/activity_main">

    <com.okason.drawingapp.CustomView
        android:id="@+id/custom_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/toolbar_bottom" />

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar_bottom"
        android:layout_width="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay"
        android:visibility="gone"/>

</RelativeLayout>

Step 2: Add Icons – you will need to choose the icons you want to represent the actions you want to perform in your app. There are few sites where you can get great looking Android Icons and I will list a few below.

  1. http://www.androidicons.com/
  2. Android Asset Studio
  3. http://icons4android.com/
  4. https://materialdesignicons.com/
  5. Google Material Icons

The icons included in this tutorial’s source code are from https://materialdesignicons.com/ all of the above options are fine, choose which ever one you like and the color you like. After you choose your icons you have to download them and then add them to your res/resource folder.

Step 3: Add Menu – now that you have your icons you actually need to add them to a menu which will then inflate into our bottom toolbar. Add a menu to your res/menu folder and call it menu_drawing.xml and here is the content of the menu with entries covering the drawing operations that we want to cover.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">
    <item
        android:id="@+id/action_erase"
        android:title="@string/action_erase"
        android:icon="@drawable/ic_eraser_white_24dp"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_delete"
        android:title="@string/action_delete"
        android:icon="@drawable/ic_delete_white_24dp"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_undo"
        android:title="@string/action_undo"
        android:icon="@drawable/ic_undo_variant_white_24dp"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_brush"
        android:title="@string/action_brush"
        android:icon="@drawable/ic_brush_white_24dp"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_color"
        android:title="@string/action_color"
        android:icon="@drawable/ic_eyedropper_variant_white_24dp"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_save"
        android:title="@string/action_save"
        android:icon="@drawable/ic_sd_white_24dp"
        app:showAsAction="always" />
</menu>

Step 4: Add Bottom Toolbar Java Code – now that we have added a menu layout with the icons that we want to add, we need to go ahead and use Java code to inflate that menu into our bottom toolbar. Update your MainActivity.java with the following code.

public class MainActivity extends AppCompatActivity {

    private Toolbar mToolbar_top;
    private Toolbar mToolbar_bottom;
    private FloatingActionButton mFab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar_top = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar_top);

        mToolbar_bottom = (Toolbar)findViewById(R.id.toolbar_bottom);
        mToolbar_bottom.inflateMenu(R.menu.menu_drawing);
        mToolbar_bottom.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                handleDrawingIconTouched(item.getItemId());
                return false;
            }
        });

        mFab = (FloatingActionButton) findViewById(R.id.fab);
        mFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mToolbar_bottom.setVisibility(View.VISIBLE);
                mFab.setVisibility(View.GONE);
            }
        });
    }

    private void handleDrawingIconTouched(int itemId) {
        switch (itemId){

        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
      
        int id = item.getItemId();
        return super.onOptionsItemSelected(item);
    }
}

Code Walkthrough – in the above code block, what we did was:

  1. Declare class instance variables for our top and button Toolbars as well as the Floating Action Button (FAB)
  2. You may want to change the Floating Action Button icon to a “+” instead of the main in XML layout
  3. We instantiated our bottom tool, added an OnMenuItemClicked listener but do not do anything with it at the moment
  4. When the FAB is clicked instead of showing the Snackbar that was added by the template we hide FAB and show our bottom toolbar

If you run your app now, it should look like this. In the next tutorial we will pick up from where we left.

If you like tutorial, please share with anyone that can benefit from it and do use the comment box to leave me a comment, ask questions or provide feedback.

Keep Coding!

 

The post Android Drawing App Tutorial – Pt. 1 appeared first on Val Okafor.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Val Okafor
Software Developer (Senior) ValOkafor.com
United States United States
My name is Val Okafor, I am a Senior Software Engineer with specialization in Android Development. Learning and problem solving is my passion and I share my Android development knowledge through my blog ValOkafor.com.

My Android courses are the courses I wish I had when I started. I teach Android development in the context of a fully developed Android app. I believe that new Android concepts are better understood if they are presented in the context of creating an app from scratch to finish.

I focus on creating Productivity Android apps and besides Android development I have 7 years’ experience as System Administrator supporting Enterprise applications and 2 years’ experience as a Web Developer building websites using PHP and ASP.Net.

I have worked for corporations such as The Home Depot, American Council on Exercise, Legend3D and HD Supply, Inc. I have a bachelor's degree in Information Technology from National University San Diego, California and a master's degree in Software Engineering from Regis University Denver, Colorado.

I enjoy sharing my extensive work experience through my blog, social media.

Comments and Discussions

 
PraiseApplaud Pin
Krunal Rohit16-Nov-15 17:47
professionalKrunal Rohit16-Nov-15 17:47 
Nice work Val Okafor Thumbs Up | :thumbsup:
Cheers
KR

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.