Nov 8, 2013

ANDROID : SIMPLE HAND DRAWING ON CANVAS WITH ERASER.

Sometimes we may need to create scratchpad in our Android application.
We can create it on CANVAS
First, create a main layout file for your activity.
<LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/drawing_question"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginLeft="40dp"
                android:layout_marginRight="30dp"
                android:background="#FFFFFF"
                android:orientation="horizontal" >

                <com.swap.handdrawing.DrawingView
                    android:id="@+id/drawing"
                    android:layout_width="0dp"
                    android:layout_height="fill_parent"
                    android:layout_marginBottom="10dp"
                    android:layout_marginRight="5dp"
                    android:layout_weight="1" >
                </com.swap.handdrawing.DrawingView>

                <LinearLayout
                    android:id="@+id/eraserView"
                    android:layout_width="50dp"
                    android:layout_height="fill_parent"
                    android:layout_marginBottom="10dp"
                    android:background="@drawable/custom_edit_text"
                    android:padding="5dp" >

                    <ImageView
                        android:id="@+id/eraser"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:layout_gravity="center"
                        android:src="@drawable/eraser" />
                </LinearLayout>
</LinearLayout>
Next, create DrawingView class extending View & implementing OnTouchListener.

 
package com.swap.handdrawing;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawingView extends View implements OnTouchListener {
 private Canvas m_Canvas;

 private Path m_Path;

 private Paint m_Paint;

 ArrayList<Pair> paths = new ArrayList<Pair>();
 
 private float mX, mY;

 private static final float TOUCH_TOLERANCE = 4;

 public static boolean isEraserActive = false; 

 public DrawingView(Context context, AttributeSet attr) {
  super(context);
  setFocusable(true);
  setFocusableInTouchMode(true);

  setBackgroundColor(Color.WHITE);

  this.setOnTouchListener(this);

  onCanvasInitialization();
 }

 public void onCanvasInitialization() {
  m_Paint = new Paint();
  m_Paint.setAntiAlias(true);
  m_Paint.setDither(true);
  m_Paint.setColor(Color.parseColor("#000000")); 
  m_Paint.setStyle(Paint.Style.STROKE);
  m_Paint.setStrokeJoin(Paint.Join.ROUND);
  m_Paint.setStrokeCap(Paint.Cap.ROUND);
  m_Paint.setStrokeWidth(2);

  m_Canvas = new Canvas();
 
  m_Path = new Path();
  Paint newPaint = new Paint(m_Paint);
  paths.add(new Pair(m_Path, newPaint));
 
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
 }

 public boolean onTouch(View arg0, MotionEvent event) {
  float x = event.getX();
  float y = event.getY();

  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   touch_start(x, y);
   invalidate();
   break;
  case MotionEvent.ACTION_MOVE:
   touch_move(x, y);
   invalidate();
   break;
  case MotionEvent.ACTION_UP:
   touch_up();
   invalidate();
   break;
  }
  return true;
 }

 @Override
 protected void onDraw(Canvas canvas) {
  for (Pair p : paths) {
   canvas.drawPath(p.first, p.second);
  }
 }

 private void touch_start(float x, float y) {

  if (isEraserActive) {
   m_Paint.setColor(Color.WHITE);
   m_Paint.setStrokeWidth(6);
   Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
   paths.add(new Pair(m_Path, newPaint));
  } else { 
   m_Paint.setColor(Color.BLACK);
   m_Paint.setStrokeWidth(2);
   Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
   paths.add(new Pair(m_Path, newPaint));
  }
 
  m_Path.reset();
  m_Path.moveTo(x, y);
  mX = x;
  mY = y;
 }

 private void touch_move(float x, float y) {
  float dx = Math.abs(x - mX);
  float dy = Math.abs(y - mY);
  if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
   m_Path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
   mX = x;
   mY = y;
  }
 }

 private void touch_up() {
  m_Path.lineTo(mX, mY);

  // commit the path to our offscreen
  m_Canvas.drawPath(m_Path, m_Paint);

  // kill this so we don't double draw
  m_Path = new Path();
  Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
  paths.add(new Pair(m_Path, newPaint));
 }   
} 
 
Then access DrawingView in your MainActivity. Toggle between eraser & pencil by changing isEraserActive & it’s image.
package com.swap.handdrawing;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

public class MainActivity extends Activity {

 private ImageView eraser;


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

  final DrawingView drawingView = (DrawingView) findViewById(R.id.drawing);

  eraser = (ImageView) findViewById(R.id.eraser);
  eraser.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {

    if (drawingView.isEraserActive) {
     drawingView.isEraserActive = false;

     eraser.setImageResource(R.drawable.eraser);

    } else {
     drawingView.isEraserActive = true;

     eraser.setImageResource(R.drawable.pencil);
    }

   }
  });

 }

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

}

 
You can get resources & drawables used in above tutorial by downloading source code. You can add colors to your drawing by changing color of path.
Any suggestions are always welcome.

Download Source Code

1 comment: