1

I am developing an android application, in this one page after filling up the details, at the end of the page i need to place some imageview or fragement in which user can able to sign thier signature it by touching. so that i can save that signature as image while clicking submit.

i have googled about this but i did not get any tutorial kind of thing to start. Please help me out from this or share some link if you guys know.

Thanks in Advance, Srikanth A this is my class file,

package com.example.test_signature;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable.Callback;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;

public class SignatureView extends SurfaceView implements OnTouchListener, Callback, android.view.SurfaceHolder.Callback {

    public SignatureView(Context context) {
            super(context);
            init();
    }

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

    private void init(){
            this.setBackgroundColor(Color.WHITE);
            mPaint = new Paint();
            mPaint.setColor(Color.BLACK);
            mPaint.setStrokeWidth(3);
            this.setOnTouchListener(this);
            this.getHolder().addCallback(this);
    }

    public void setStrokeWidth(float width){
            mPaint.setStrokeWidth(width);
            this.invalidate();
    }

    public void setColor(int color){
            mPaint.setColor(color);
            this.invalidate();
    }

    public void clear(){
            mDots = new ArrayList<List<Dot>>();
            //To prevent an exception
            mDots.add(new ArrayList<Dot>());
            this.invalidate();
    }

    private List<List<Dot>> mDots = new ArrayList<List<Dot>>();

    private class Dot{

            public float X = 0;
            public float Y = 0;

            public Dot(float x, float y){
                    X = x;
                    Y = y;
            }
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
            //mLastActivity = Calendar.getInstance();
            switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                    mDots.add(new ArrayList<Dot>());
                    mDots.get(mDots.size() - 1).add(new Dot(event.getX(), event.getY()));
                    this.invalidate();
                    break;
            case MotionEvent.ACTION_UP:
                    mDots.get(mDots.size() - 1).add(new Dot(event.getX(), event.getY()));
                    this.invalidate();
                    break;
            case MotionEvent.ACTION_MOVE:
                    mDots.get(mDots.size() - 1).add(new Dot(event.getX(), event.getY()));
                    this.invalidate();
                    break;
            }
            return true;
    }

    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {

    }

    public void surfaceCreated(SurfaceHolder arg0) {

    }

    public void surfaceDestroyed(SurfaceHolder arg0) {

    }

    public Paint mPaint;
    @Override
    protected void onDraw(Canvas canvas) {
            for(List<Dot> dots : mDots){
                for(int i = 0; i < dots.size(); i++){
                    if(i - 1 == -1)
                            continue;
                    canvas.drawLine(dots.get(i - 1).X, dots.get(i - 1).Y, dots.get(i).X, dots.get(i).Y, mPaint);
                }
            }
    }

    public Bitmap getBitmap(){
            Bitmap b = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888); 
        Canvas c = new Canvas(b);
        this.draw(c);
        return b;
    }

    public boolean exportFile(String pathString, String fileString){
            File path = new File(pathString);
            path.mkdirs();
            if(!fileString.toLowerCase(Locale.ENGLISH).contains(".png")){
                    fileString += ".png";
            }
            File file = new File(path, fileString);
            FileOutputStream out;
            try {
                    out = new FileOutputStream(file);
            this.getBitmap().compress(Bitmap.CompressFormat.PNG, 90, out);
            return true;
            } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
            return false;
    }
}

this is My XML file in which i have created the view for the user to put a signature.

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".SignatureView" >    

    <View
        android:id="@+id/id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <com.example.test_signature.SignatureView
        android:id="@+id/signature"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:height="18dp"
        android:width="18dp" />

</RelativeLayout>

i have created this sample to test the signature functionality. But whenever i run this code, my application get crashes. Anyone please help me out. I think i have done a mistake in my XML.

@FabianCook : pla look out the code i have pasted. I'hv followed your procedure oly. but can u pls tel me wats the problem in the code ?

I have edited my XML file as you suggested, but still my application getting crashes whenever i open.

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".SignatureView" >    

    <View
        android:id="@+id/id"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.example.test_signature.SignatureView
        android:id="@+id/signature"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
         />




</RelativeLayout>
  • Height and width in android are `android:layout_width="wrap_content" android:layout_height="wrap_content"` change these to `android:layout_width="match_parent" android:layout_height="match_parent"` android remove `android:height="18dp" android:width="18dp"` – FabianCook Nov 05 '13 at 06:00
  • can anyone give the answer of this equation http://stackoverflow.com/questions/34490353/in-android-how-can-i-get-screenshot-or-bitmap-from-custom-surface-view – hardik lakhani Dec 29 '15 at 05:32

2 Answers2

5
public class SignatureView extends SurfaceView implements OnTouchListener, Callback {

        public SignatureView(Context context) {
                super(context);
                init();
        }

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

        private void init(){
                this.setBackgroundColor(Color.WHITE);
                mPaint = new Paint();
                mPaint.setColor(Color.BLACK);
                mPaint.setStrokeWidth(3);
                this.setOnTouchListener(this);
                this.getHolder().addCallback(this);
        }

        public void setStrokeWidth(float width){
                mPaint.setStrokeWidth(width);
                this.invalidate();
        }

        public void setColor(int color){
                mPaint.setColor(color);
                this.invalidate();
        }

        public void clear(){
                mDots = new ArrayList<List<Dot>>();
                //To prevent an exception
                mDots.add(new ArrayList<Dot>());
                this.invalidate();
        }

        private List<List<Dot>> mDots = new ArrayList<List<Dot>>();

        private class Dot{

                public float X = 0;
                public float Y = 0;

                public Dot(float x, float y){
                        X = x;
                        Y = y;
                }
        }

        @Override
        public boolean onTouch(View view, MotionEvent event) {
                //mLastActivity = Calendar.getInstance();
                switch(event.getAction()){
                case MotionEvent.ACTION_DOWN:
                        mDots.add(new ArrayList<Dot>());
                        mDots.get(mDots.size() - 1).add(new Dot(event.getX(), event.getY()));
                        this.invalidate();
                        break;
                case MotionEvent.ACTION_UP:
                        mDots.get(mDots.size() - 1).add(new Dot(event.getX(), event.getY()));
                        this.invalidate();
                        break;
                case MotionEvent.ACTION_MOVE:
                        mDots.get(mDots.size() - 1).add(new Dot(event.getX(), event.getY()));
                        this.invalidate();
                        break;
                }
                return true;
        }

        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {

        }

        @Override
        public void surfaceCreated(SurfaceHolder arg0) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder arg0) {

        }

        public Paint mPaint;
        @Override
        protected void onDraw(Canvas canvas) {
                for(List<Dot> dots : mDots){
                    for(int i = 0; i < dots.size(); i++){
                        if(i - 1 == -1)
                                continue;
                        canvas.drawLine(dots.get(i - 1).X, dots.get(i - 1).Y, dots.get(i).X, dots.get(i).Y, mPaint);
                    }
                }
        }

        public Bitmap getBitmap(){
                Bitmap b = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888); 
            Canvas c = new Canvas(b);
            this.draw(c);
            return b;
        }

        public boolean exportFile(String pathString, String fileString){
                File path = new File(pathString);
                path.mkdirs();
                if(!fileString.toLowerCase(Locale.ENGLISH).contains(".png")){
                        fileString += ".png";
                }
                File file = new File(path, fileString);
                FileOutputStream out;
                try {
                        out = new FileOutputStream(file);
                this.getBitmap().compress(Bitmap.CompressFormat.PNG, 90, out);
                return true;
                } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                return false;
        }
}

I think the code explains its self

This code takes care of everything. Has some nice little functions for different things like saving the image to a file etc.

Place this in one of your packages, and then in your XML file replace

<View android:id="@+id/id"/>

with

<package.name.SignatureView android:id="@+id/id"/>

USAGE

Create a new class in your package called SignatureView, delete everything in this file except for the first line, you should be left with package your.package.name

On the third line paste the code above and press Ctrl-Shift-O and it will import everything you need.

Save this file and then build your project.

In your XML file use:

<your.package.name.SignatureView 
    android:id="@+id/signature" 
    android:width="match_parent"
    android:height="match_parent"/>

Save this and build your project.

In your activity you can use:

SignatureView mSignature;

mSignature = (SignatureView) this.findViewById(R.id.signature);

And then access the functions you need to save the signature to a file:

mSignature.exportFile("/mnt/sdcard/", "signaturefile.png");
FabianCook
  • 20,269
  • 16
  • 67
  • 115
  • Hi FabianCook, thanks a lot for your fastest response. I am waiting :) – user2931394 Oct 29 '13 at 09:26
  • hi, thanks man for this code.. i hope this codde will save my huge effort. One more very basic doubt. In XML what kind of input i need to give top proceed with this class, can u pls share that too ?? – user2931394 Oct 29 '13 at 09:29
  • Any questions just ask – FabianCook Oct 29 '13 at 09:30
  • What package have you put this class in? – FabianCook Oct 29 '13 at 09:31
  • In my XML i have series of input to get from the user, at the end of that XML page i need to get this signature input from the user and save it accordingly into db. the submit click fr the page will be called in separate class. So where i need to place the class u hv given ? – user2931394 Oct 29 '13 at 09:38
  • thanks buddy, i will try this and update you the result. If i got any doubt means will let u knw. Thanks fr ur help. – user2931394 Oct 29 '13 at 09:41
  • - this one i need to place in my XML file ? - where i need to place this one on the same XMl ? or "Place this in one of your packages, and then in your XML file replace" i dint get wat u mentioned here. I have oly one package. Inside my package where i need to paste this whether in androidmanifest.XML or or in the design XML ? – user2931394 Oct 29 '13 at 09:48
  • 1
    thanks fr the step by step reply and ur tolerance towards the new developers. thanks man :) – user2931394 Oct 29 '13 at 10:55
  • If the answer is correct please press the tick on the answer, when it goes green you have chosen that answer as correct, thanks – FabianCook Oct 29 '13 at 19:23
  • yes sure, tonight im going try your code. After that i wil mark it as green. Thanks :) – user2931394 Oct 30 '13 at 10:30
  • i have edited the question with my code, pls look into that and suggest wat i did wrongly. – user2931394 Nov 05 '13 at 05:42
  • i have modified the XML as you suggested. Still my application getting crash. Pls look into that and tel me how to proceed. – user2931394 Nov 05 '13 at 18:00
  • Please post the stack trace, I need that to be able to tell you what is wrong. – FabianCook Nov 05 '13 at 20:11
  • http://stackoverflow.com/questions/4957730/finding-stack-trace-in-eclipse-with-android – FabianCook Nov 05 '13 at 20:12
1

hope this code helps you:)

esign_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >


    <android.gesture.GestureOverlayView
        android:id="@+id/signaturePad"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="5"
        android:background="@android:color/white"
        android:clickable="false"
        android:eventsInterceptionEnabled="true"
        android:fadeEnabled="false"
        android:gestureColor="#0000ff"
        android:gestureStrokeLengthThreshold="0.1"
        android:gestureStrokeType="multiple"
        android:longClickable="false"
        android:orientation="vertical"
        android:uncertainGestureColor="#000000"
        android:splitMotionEvents="true" 
        android:fadeOffset="10000000">

    </android.gesture.GestureOverlayView>

    <RelativeLayout
        android:id="@+id/rellay_esign_donebutton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
         >
 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        >
        <Button
            android:id="@+id/DoneButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Done" />

         <Button
             android:id="@+id/ClearButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="Clear" />
</LinearLayout>
    </RelativeLayout>

</LinearLayout>

Esignature.java

public class Esignature extends Activity {
    GestureOverlayView gestureView;
    String path;
    File file;
    Bitmap bitmap;
    public boolean gestureTouch=false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.esign_main);



        Button donebutton = (Button) findViewById(R.id.DoneButton);
        donebutton.setText("Done");
        Button clearButton = (Button) findViewById(R.id.ClearButton);
        clearButton.setText("Clear");

        path=Environment.getExternalStorageDirectory()+"/signature.png";
        file = new File(path);
        file.delete();
        gestureView = (GestureOverlayView) findViewById(R.id.signaturePad);
        gestureView.setDrawingCacheEnabled(true);

        gestureView.setAlwaysDrawnWithCacheEnabled(true);
        gestureView.setHapticFeedbackEnabled(false);
        gestureView.cancelLongPress();
        gestureView.cancelClearAnimation();
        gestureView.addOnGestureListener(new OnGestureListener() {

            @Override
            public void onGesture(GestureOverlayView arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onGestureCancelled(GestureOverlayView arg0,
                    MotionEvent arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onGestureEnded(GestureOverlayView arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onGestureStarted(GestureOverlayView arg0,
                    MotionEvent arg1) {
                // TODO Auto-generated method stub
                if (arg1.getAction()==MotionEvent.ACTION_MOVE){
                    gestureTouch=false;                     
             }
             else 
             {
                    gestureTouch=true;
            }
            }});

        donebutton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                try {
                    bitmap = Bitmap.createBitmap(gestureView.getDrawingCache());
                    file.createNewFile();
                    FileOutputStream fos = new FileOutputStream(file);
                    fos = new FileOutputStream(file);
                    // compress to specified format (PNG), quality - which is
                    // ignored for PNG, and out stream
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            if(gestureTouch==false)
            {
                setResult(0);
                finish();
            }
            else
            {
                setResult(1);
                finish();
            }
            }
        });

        clearButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                gestureView.invalidate();
                gestureView.clear(true);
                gestureView.clearAnimation();
                gestureView.cancelClearAnimation();
            }
        });
    }

}

Harshal Benake
  • 2,391
  • 1
  • 23
  • 40