Search code examples
javaandroiddrawpaintsignature

Signatures in Android


I want to make a class which captures a human signature for my Android app. I have this code so far:

public class DrawView extends View implements OnTouchListener {
    private static final String TAG = "DrawView";

    List<Point> points = new ArrayList<Point>();
    Paint paint = new Paint();
    long oldTime = 0;

    public DrawView(Context context) {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);

        this.setOnTouchListener(this);

        // paint.setColor(Color.BLACK);
        // paint.setAntiAlias(true);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(2);
        paint.setColor(Color.BLACK);
    }

    @Override
    public void onDraw(Canvas canvas) {
        Path path = new Path();

        if (points.size() > 1) {
            for (int i = points.size() - 2; i < points.size(); i++) {
                if (i >= 0) {
                    Point point = points.get(i);

                    if (i == 0) {
                        Point next = points.get(i + 1);
                        point.dx = ((next.x - point.x) / 3);
                        point.dy = ((next.y - point.y) / 3);
                    } else if (i == points.size() - 1) {
                        Point prev = points.get(i - 1);
                        point.dx = ((point.x - prev.x) / 3);
                        point.dy = ((point.y - prev.y) / 3);
                    } else {
                        Point next = points.get(i + 1);
                        Point prev = points.get(i - 1);
                        point.dx = ((next.x - prev.x) / 3);
                        point.dy = ((next.y - prev.y) / 3);
                    }
                }
            }
        }

        boolean first = true;
        for (int i = 0; i < points.size(); i++) {
            Point point = points.get(i);
            if (first) {
                first = false;
                path.moveTo(point.x, point.y);
            } else {

                Point prev = points.get(i - 1);
                path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x
                        - point.dx, point.y - point.dy, point.x, point.y);

            }
        }
        canvas.drawPath(path, paint);

    }

    public boolean onTouch(View view, MotionEvent event) {
        if (event.getAction() != MotionEvent.ACTION_UP) {
            Point point = new Point();
            point.x = event.getX();
            point.y = event.getY();
            points.add(point);
            invalidate();
            return true;
        }
        return super.onTouchEvent(event);

    }

    public boolean checkTime() {
        //Check if there was an input 400 ms ago
        long newTime = System.currentTimeMillis();
        long diffirence = newTime - oldTime;
        if (oldTime == 0) {
            oldTime = System.currentTimeMillis();
            return true;
        } else if (diffirence <= 400) {
            oldTime = System.currentTimeMillis();
            return true;
        }
        return false;
    }
}

class Point {
    float x, y;
    float dx, dy;

    @Override
    public String toString() {
        return x + ", " + y;
    }
}

The problem is that the line will connect to the latest point when I start drawing again, even when I stop drawing for a while. This is of course not very useful for capturing human signatures, that's why I created the checkTime method. If you stop drawing for 400ms it returns false, when you start drawing again it will start a new line which is not connected to the old line. I only just don't know how I can implement my method, I tried a lot but the line keeps connecting to the latest point, maybe someone can help me.


Solution

  • I used this post from Lars Vogel, but many thanks to Marc Van Daele!

    This is code wich paints the View:

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class SingleTouchEventView extends View {
      private Paint paint = new Paint();
      private Path path = new Path();
    
      public SingleTouchEventView(Context context, AttributeSet attrs) {
        super(context, attrs);
    
        paint.setAntiAlias(true);
        paint.setStrokeWidth(6f);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
      }
    
      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawPath(path, paint);
      }
    
      @Override
      public boolean onTouchEvent(MotionEvent event) {
        float eventX = event.getX();
        float eventY = event.getY();
    
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
          path.moveTo(eventX, eventY);
          return true;
        case MotionEvent.ACTION_MOVE:
          path.lineTo(eventX, eventY);
          break;
        case MotionEvent.ACTION_UP:
          // nothing to do
          break;
        default:
          return false;
        }
    
        // Schedules a repaint.
        invalidate();
        return true;
      }
    } 
    

    You have to call this activity to start paiting:

    import android.app.Activity;
    import android.os.Bundle;
    
    public class SingleTouchActivity extends Activity {
    
    /** Called when the activity is first created. */
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SingleTouchEventView(this, null));
      }
    }