Monday, October 29, 2012

Draw line on finger touch

There are many application in Android you can use to draw something on screen. This is a simple application which will draw straight line on screen between touch you have started and the last point of your touch. 

This application will use Bitmap, Canvas, and Paint class.

Bitmap class covers some common techniques for processing and loading Bitmap objects in a way that keeps your user interface (UI) components responsive and avoids exceeding your application memory limit. 

Canvas class holds the DRAW calls. To draw something, you need four 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, Circle), and a paint (to describe the colours and styles for the drawing).

Paint class holds the style and colour information about how to draw geometries, text and bitmaps.
 
1. Design Screen: 

activity_touch_draw.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>

An ImageView will be used as drawing board and your finger will work as pencil. A straight line will drawn from starting touch to ending point where user pull up finger. 

TouchDraw.java
package app.test;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class Test extends Activity implements OnTouchListener {
  ImageView imageView;
  Bitmap bitmap;
  Canvas canvas;
  Paint paint;
  float downx = 0, downy = 0, upx = 0, upy = 0;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    imageView = (ImageView) this.findViewById(R.id.ImageView);

    Display currentDisplay = getWindowManager().getDefaultDisplay();
    float dw = currentDisplay.getWidth();
    float dh = currentDisplay.getHeight();

    bitmap = Bitmap.createBitmap((int) dw, (int) dh,
        Bitmap.Config.ARGB_8888);
    canvas = new Canvas(bitmap);
    paint = new Paint();
    paint.setColor(Color.GREEN);
    imageView.setImageBitmap(bitmap);

    imageView.setOnTouchListener(this);
  }

  public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
      downx = event.getX();
      downy = event.getY();
      break;
    case MotionEvent.ACTION_MOVE:
      break;
    case MotionEvent.ACTION_UP:
      upx = event.getX();
      upy = event.getY();
      canvas.drawLine(downx, downy, upx, upy, paint);
      imageView.invalidate();
      break;
    case MotionEvent.ACTION_CANCEL:
      break;
    default:
      break;
    }
    return true;
  }
}

First of all you'll need to know what is width and height of your screen. You'll need Display class object to get detail about screen. Display class provides information about the display size and density.   


Display currentDisplay = getWindowManager().getDefaultDisplay();
float dw = currentDisplay.getWidth();
float dh = currentDisplay.getHeight();

currentDisplay object will provider display width and height.
bitmap object will of provided width and height.
canvas object will used to class draw functions. Your actual line will draw on canvas.
paint object will actually a line on the canvas.

Finally, user will draw on screen line by touching ImageView object. So, I have set OnTouchListener on ImageView object.

OnTouchListener is an interface definition for a callback to be invoked when a touch event is dispatched to the view.

onTouch method is called when a touch event is dispatched to a view. This allows a listeners to get chance to respond before the target view.
public boolean onTouch(View v, MotionEvent event)

  • is object of View class from where touch is dispatched.  
  • event is object of MotionEvent containing full information about event

int action = event.getAction();

getAction() return the kind of action being performed. During entire process of drawing a line on touch many actions will be called like.

  • ACTION_DOWN
  • ACTION_MOVE
  • ACTION_CANCEL
  • ACTION_UP

So, I need to draw a line starting from action called ACTION_DOWN up to the action ACTION_UP. I have taken starting X & Y co-ordinate where ACTION_DOWN action called and again I have retrieved ending X & Y co-ordinate when ACTION_UP action called. Finally, I have used drawLine() method of Canvas class to draw straight line.

34 comments:

  1. nice tutorial
    how to draw a line along finger

    ReplyDelete
    Replies
    1. Thanx, its very simple to draw line along finger.
      Instead of drawing a line in case statement MotionEvent.ACTION_UP event, you need to draw a very small circle in case statement MotionEvent.ACTION_MOVE event. That will draw a thick line along with your finger touch.

      Delete
    2. shouldn't it be like this?

      setContentView(R.layout.activity_touch_draw);

      Delete
  2. hi, Its a nice tutorial indeed. I'm having a problem that It doesnot draw line on proper mouse point OR touch point. How can i solve this problem?

    ReplyDelete
    Replies
    1. Is your line doesn't come on the place where you touch or its not coming just smoother.

      Delete
    2. My line doesn't come on the place where i touch :\

      Delete
    3. Check out your DRAWLINE() method friend or mail me your code.

      Delete
    4. Even my line doesn't come at the place where i touch. There is always some distance between them which is not constant

      Delete
    5. I am also having the same problem that Harshal and Killer talks about. Another problem is that the canvas does not cover the whole image area where as the imageview has been set to fill-parent(width,height).

      Delete
    6. This comment has been removed by the author.

      Delete
  3. the line is not continuous, it is appearing like a dotted line how can I make it as a continuous line

    ReplyDelete
    Replies
    1. Hello friend. Its just happening because we normally move finger faster where as code can't execute at that speed. To solve your problem try to draw adjacent point of X & Y point. May this solve your problem.

      Delete
    2. Hi! I've done it in such way. First - add these variables
      float startX = 0;
      float startY = 0;
      float endX = 0;
      float endY = 0;

      Then, modify your switch like this

      switch (action) {
      case MotionEvent.ACTION_DOWN:
      startX=event.getX();
      startY=event.getY();
      break;
      case MotionEvent.ACTION_MOVE:
      endX = event.getX();
      endY = event.getY();
      canvas.drawLine(startX,startY,endX,endY, paint);
      imageView.invalidate();
      startX=endX;
      startY=endY;
      break;
      case MotionEvent.ACTION_UP:
      break;
      case MotionEvent.ACTION_CANCEL:
      break;
      default:
      break;
      }
      But I should mention, that I get not smoothy line, but it's solid.

      Delete
  4. Sharad, you still continue to respond to this post? I have a big question.
    thank you

    ReplyDelete
  5. I want draw straight line on image.Its look like height or width of image

    Example URL : https://itunes.apple.com/us/app/measured-measure.-store.-share./id488749934?mt=8

    you can see this..

    waiting for your replay..

    thanks in advance..

    ReplyDelete
    Replies
    1. Mayur, To make something look a like first you have to heading to Maths. I sorry but I am not aware about that much mathematical measurement. I can help you out in android queries but not in mathematical solutions.

      Delete
  6. My line doesn't come on the place where i touch :\ please post the changed or correct code

    ReplyDelete
    Replies
    1. I faced the same issue when I was drawing over the screenshot that I took.

      This occurs because the ImageView is bigger than the Bitmap of the screenshot (to maintain aspect ratio, the ImageView doesn't fill the width. You can confirm it by setting a colour background of the ImageView).

      So I basically did following the steps.

      1. add this to the onCreate():

      myImageView.getViewTreeObserver();
      vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
      public boolean onPreDraw() {
      mImageView.getViewTreeObserver().removeOnPreDrawListener(this);

      wrapWidthOfImageViewToBitmap();
      mScale = 1f * mOriginalBitmap.getHeight() / mImageView.getHeight();

      mAlteredBitmap = Bitmap.createBitmap(mOriginalBitmap.getWidth(), mOriginalBitmap.getHeight(), mOriginalBitmap.getConfig());

      mCanvas = new Canvas(mAlteredBitmap);
      mPaint = new Paint();
      mPaint.setColor(Color.GREEN);
      mPaint.setStrokeWidth(5);
      mMatrix = new Matrix();
      mCanvas.drawBitmap(mOriginalBitmap, mMatrix, mPaint);

      mImageView.setImageBitmap(mAlteredBitmap);

      return true;
      }
      });

      2. And added this helper method:

      private void wrapWidthOfImageViewToBitmap() {
      mImageView.getLayoutParams().width = mOriginalBitmap.getWidth() * mImageView.getHeight() / mOriginalBitmap.getHeight();
      }

      3. declared the following field:
      private float mScale;

      4. Then in the onTouch(), I replace:

      a. `event.getX()` with `event.getX() * mScale`, and
      b. `event.getY()` with `event.getY() * mScale`

      Now what I draw shows up where I want it to.

      Delete
  7. Replies
    1. Did u solve the problem? I spent so much time on this....

      I found that creating bitmap on Layout change solves the problem.
      i.e. change the onCreate() to:

      public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_touch_draw);

      /* set up Paint */
      paint = new Paint();
      paint.setColor(Color.BLACK);
      paint.setStrokeWidth((float) 3);

      /* Create bitmap */
      imageView = (ImageView) this.findViewById(R.id.imageView);
      imageView.setOnTouchListener(this);

      imageView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
      @Override
      public void onLayoutChange(View v, int left, int top, int right, int bottom,
      int oldLeft, int oldTop, int oldRight, int oldBottom) {
      // its possible that the layout is not complete in which case
      // we will get all zero values for the positions, so ignore the event
      if (left == 0 && top == 0 && right == 0 && bottom == 0) {
      return;
      }

      // Do what you need to do with the height/width since they are now set
      bitmap = Bitmap.createBitmap(right - left + 1, bottom - top + 1, Bitmap.Config.ARGB_8888);
      canvas = new Canvas(bitmap);
      Log.d("DrawLineOnFingerTouch", left + " " + top + " " + right + " " + bottom);
      paint = new Paint();
      paint.setColor(Color.BLACK);
      paint.setStrokeWidth((float) 3);
      imageView.setImageBitmap(bitmap);
      }
      });

      }


      Delete
  8. How can we draw continuous straight line(not ZigZag)

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Here's what you need. In order to plot the missing points you should query for the historical points (x,y) along with the other points. These are the points that form the intermediate skipped points. Search the internet on these lines and you should find some example implementing the same. Good Luck.

    ReplyDelete
  11. Working fine.
    But how to save as image?

    ReplyDelete
  12. Hi Could you please tell me how to draw arrow using finger?

    ReplyDelete
  13. Hi friends .. need one help how to draw over image please give idea how to implement..

    ReplyDelete
  14. i want this type of code finger touch feedback ontouch ImageView in androud

    ReplyDelete
  15. How to save as image?
    Thanks in advance

    ReplyDelete
  16. Hi I can draw the line But the image is not preview when use this code. I don't know what is the problem. Can you guide me

    ReplyDelete