Android上自定義View實現電子簽名功能

近來項目中遇到了實現電子簽名的功能,現在已經完成,覺得可以,故把這一個模塊抽取出來一個demo,供大家看看有什麼可改進的。代碼寫的比較簡單,代碼就是註釋,下面上效果圖:


下面是代碼

package com.hai.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 可以簽名的view
 * Created by 黃海 on 2016/6/14.
 */
public class SignatureView extends View {
    private static final String TAG = "SignatureView";
    private Paint mPathPaint;
    private Paint mBitmapPaint;
    private Canvas mCanvas;
    private Path mPath;
    private Bitmap mBitmap;
    /**
     * 畫圖區域的最大位置
     */
    private float mSmallX = 0, mSmallY = 0, mBigX = 0, mBigY = 0;
    private float mPreX, mPreY;

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

    private void init() {
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPathPaint.setDither(true);
        mPathPaint.setStyle(Paint.Style.STROKE);
        mPathPaint.setStrokeWidth(10);
        mPathPaint.setColor(Color.parseColor("#ff3f4a57"));
        mPathPaint.setStrokeJoin(Paint.Join.ROUND);//線段結束處的形狀
        mPathPaint.setStrokeCap(Paint.Cap.ROUND);//線段開始結束處的形狀
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        resetSign();
    }

    private void resetSign() {
        mPath = new Path();
        mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        mBitmap.eraseColor(Color.TRANSPARENT);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, mPathPaint);
    }

    /**
     * 計算畫圖區域的位置
     *
     * @param x
     * @param y
     */
    private void computeDrawMaxRang(float x, float y) {
        if (mSmallX == 0 && mSmallY == 0 && mBigX == 0 && mBigY == 0) {
            mSmallX = mBigX = x;
            mBigY = mSmallY = y;
        } else {
            mSmallX = Math.min(mSmallX, x);
            mSmallY = Math.min(mSmallY, y);
            mBigX = Math.max(mBigX, x);
            mBigY = Math.max(mBigY, y);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPreX = event.getX();
                mPreY = event.getY();
                computeDrawMaxRang(mPreX, mPreY);
                mPath.reset();
                mPath.moveTo(mPreX, mPreY);
                break;
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                float y = event.getY();
                computeDrawMaxRang(x, y);
                //繪製圓滑曲線(貝塞爾曲線)
                mPath.quadTo(mPreX, mPreY, x, y);
                mPreX = x;
                mPreY = y;
                break;
            case MotionEvent.ACTION_UP:
                computeDrawMaxRang(event.getX(), event.getY());
                mPath.lineTo(event.getX(), event.getY());
                mCanvas.drawPath(mPath, mPathPaint);
                break;
        }
        invalidate();
        return true;
    }

    /**
     * 保存bitmap到文件
     *
     * @param fileapth
     * @return 成功返回true,反之false
     */
    public boolean SaveBitmapToFile(String fileapth) {
        File file = new File(fileapth);
        if (file.exists()) {
            float signAreaWidth = mBigX - mSmallX;
            float signAreaHeight = mBigY - mSmallY;
            Bitmap bitmap = Bitmap.createBitmap(mBitmap, (int) mSmallX, (int) mSmallY, (int) signAreaWidth, (int) signAreaHeight, new Matrix(), true);
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                return true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return false;
            } finally {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else
            return false;
    }

    public void reset() {
        resetSign();
        invalidate();
    }
}

Acitivty代碼

package com.hai.activity;

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.PopupWindow;

import com.hai.R;
import com.hai.widget.SignatureView;

/**
 * Created by 黃海 on 2016/5/24.
 */
public class MyTest extends Activity implements View.OnClickListener {
    Button btn;
    PopupWindow popupWindow;
    SignatureView signatureView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mytest);
         btn = (Button) findViewById(R.id.btn);
    }

    public void clk(View v) {

        popupWindow = new PopupWindow(this);
        popupWindow.setContentView(View.inflate(this,R.layout.popupwindow,null));
        popupWindow.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        popupWindow.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
        popupWindow.showAtLocation(btn, Gravity.CENTER,0,0);
        View view=popupWindow.getContentView();
        signatureView= (SignatureView) view.findViewById(R.id.signView);
        view.findViewById(R.id.btn_cancel).setOnClickListener(this);
        view.findViewById(R.id.btn_reset).setOnClickListener(this);
        view.findViewById(R.id.btn_ok).setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_cancel:
                if (popupWindow!=null&&popupWindow.isShowing()){
                    popupWindow.dismiss();
                }
                break;

            case R.id.btn_reset:
                signatureView.reset();
                break;
        }
    }
}


彈出窗口布局

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

    <com.hai.widget.SignatureView
        android:id="@+id/signView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#AAF6EA7F" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="sure" />

        <Button
            android:id="@+id/btn_reset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="reset" />

        <Button
            android:id="@+id/btn_cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="cancel" />
    </LinearLayout>

</LinearLayout>





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章