Wednesday, May 7, 2014

Android: Draw On Screen By Finger

In today's post I want to show, how to program an Android application using C#, which allows it to draw on the screen, more precisely the app window. Just like in a drawing or hand writing app.

For that we create a custom View, which we use of course in the MainActivity as layout then.
In the view we define on startup or when its size changes the drawing area:

protected override void OnSizeChanged (int w, int h, int oldw, int oldh)
{
     base.OnSizeChanged (w, h, oldw, oldh);
     canvasBitmap = Bitmap.CreateBitmap (w, h, Bitmap.Config.Argb8888);
     drawCanvas = new Canvas (canvasBitmap);
}

canvasBitmap is a bitmap variable, which contains the image drawn so far. drawCanvas is a canvas variable, which is linked to the bitmap.

Further we use a drawing path (Path). With this we save and draw paths the user paints on the screen. With the function OnTouchEvent(), which is called when the display is touched, we track the moves of the user:

public override  bool OnTouchEvent (MotionEvent e)
{
     float touchX = e.GetX ();
     float touchY = e.GetY ();
     switch (e.Action) {
     case MotionEventActions.Down:
          drawPath.MoveTo (touchX, touchY);
          break;
     case MotionEventActions.Move:
          drawPath.LineTo (touchX, touchY);
          break;
     case MotionEventActions.Up:
          drawCanvas.DrawPath (drawPath, drawPaint);
          drawPath.Reset ();
          break;
     default:
          return false;
     }
     Invalidate ();
     return true;
}

In the function first the right action is determined: If the user touches the display (for this path) for the first time, the drawing path is moved to this point without drawing. If the user moves his finger further from this position on, the path is drawn along. At the end of the drawing process, the path is saved in drawCanvas. Since this is connected to canvasBitmap, the path is still drawn later when it is already one. Via Invalidate() we force a redraw of the screen.

Finally we have to override the OnDraw() function:
protected override void OnDraw (Canvas canvas)
{
     canvas.DrawBitmap (canvasBitmap, 0, 0, canvasPaint);
     canvas.DrawPath (drawPath, drawPaint);
}

Here first canvasBitmap is drawn to draw the whole picture created so far, as well as drawPath to show the current, not yet finished path.

At the beginning, the function start() has to be called to set different values like drawing color, background color, pen width etc.
I think a look at the whole source code should make everything clear:

MainActivity.cs:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

namespace Draw
{
     [Activity (Label = "Draw", MainLauncher = true)]
     public class MainActivity : Activity
     {
          int count = 1;

          protected override void OnCreate (Bundle bundle)
          {
               base.OnCreate (bundle);

               DrawView test = new DrawView(this);
               test.start ();

               SetContentView (test);
          }
     }
}

DrawView.cs:
using System;
using Android.Views;
using Android.Graphics;
using System.Collections.Generic;
using Android.Content;
using Java.Lang;

namespace Draw
{
     public class DrawView : View
     {
          public DrawView (Context context) : base (context)
          {

          }

          private Path drawPath;
          private Paint drawPaint, canvasPaint;
          private uint paintColor = 0xFF660000;
          private Canvas drawCanvas;
          private Bitmap canvasBitmap;


          public void start ()
          {
               drawPath = new Path ();
               drawPaint = new Paint ();
               drawPaint.Color = new Color ((int)paintColor);
               drawPaint.AntiAlias = true;
               drawPaint.StrokeWidth = 20;
               drawPaint.SetStyle (Paint.Style.Stroke);
               drawPaint.StrokeJoin = Paint.Join.Round;
               drawPaint.StrokeCap = Paint.Cap.Round;
               canvasPaint = new Paint ();
               canvasPaint.Dither = true;
          }

          protected override void OnSizeChanged (int w, int h, int oldw, int oldh)
          {
               base.OnSizeChanged (w, h, oldw, oldh);
               canvasBitmap = Bitmap.CreateBitmap (w, h, Bitmap.Config.Argb8888);
               drawCanvas = new Canvas (canvasBitmap);
          }

          protected override void OnDraw (Canvas canvas)
          {
               canvas.DrawBitmap (canvasBitmap, 0, 0, canvasPaint);
               canvas.DrawPath (drawPath, drawPaint);
          }
              

          public override  bool OnTouchEvent (MotionEvent e)
          {
               float touchX = e.GetX ();
               float touchY = e.GetY ();
               switch (e.Action) {
               case MotionEventActions.Down:
                    drawPath.MoveTo (touchX, touchY);
                    break;
               case MotionEventActions.Move:
                    drawPath.LineTo (touchX, touchY);
                    break;
               case MotionEventActions.Up:
                    drawCanvas.DrawPath (drawPath, drawPaint);
                    drawPath.Reset ();
                    break;
               default:
                    return false;
               }
               Invalidate ();
               return true;
          }
     }
}

Finally a picture:

3 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. How to Clear Draw Previous image and Draw New Image

    ReplyDelete
  3. awesome thanks!

    ReplyDelete