Android 实例:手写签名

根据(https://github.com/Geek8ug/SignatureView ) 整理

1.画笔工具类 SignatureView:

public class SignatureView extends View {
    
    
    private Context mContext;
    private int targetWidth = 100, targetHeight = 100;
    private ISignatureCallBack signatureCallBack;

    public void setSignatureCallBack(ISignatureCallBack signatureCallBack) {
    
    
        this.signatureCallBack = signatureCallBack;
    }

    /**
     * 笔画X坐标起点
     */
    private float mX;
    /**
     * 笔画Y坐标起点
     */
    private float mY;
    /**
     * 手写画笔
     */
    private final Paint mGesturePaint = new Paint();
    /**
     * 路径
     */
    private final Path mPath = new Path();
    /**
     * 签名画笔
     */
    private Canvas cacheCanvas;
    /**
     * 签名画布
     */
    private Bitmap cachebBitmap;
    /**
     * 画笔宽度 px;
     */
    private int mPaintWidth = 10;
    /**
     * 前景色
     */
    private int mPenColor = Color.BLACK;
    /**
     * 背景色(指最终签名结果文件的背景颜色,默认为透明色)
     */
    private int mBackColor = Color.WHITE;

    /**
     * 是否签字
     */
    private boolean isDown = false;


    public SignatureView(Context context) {
    
    
        super(context);
        this.mContext = context;
        init(context);
    }

    public SignatureView(Context context, AttributeSet attrs) {
    
    
        super(context, attrs);
        this.mContext = context;
        init(context);
    }

    public SignatureView(Context context, AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        init(context);
    }

    public void init(Context context) {
    
    
        this.mContext = context;
        mGesturePaint.setAntiAlias(true);//抗锯齿
        mGesturePaint.setStyle(Paint.Style.STROKE);
        mGesturePaint.setStrokeWidth(mPaintWidth);
        mGesturePaint.setColor(mPenColor);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    
    
        switch (event.getAction()) {
    
    
            case MotionEvent.ACTION_DOWN:
                touchDown(event);
                break;
            case MotionEvent.ACTION_MOVE:
                touchMove(event);
                break;
            case MotionEvent.ACTION_UP:
                Log.e("TAG", "onTouchEventup");
                isDown = true;
                break;
        }
        // 更新绘制
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
    
    
        super.onDraw(canvas);
        canvas.drawPath(mPath, mGesturePaint);
    }

    private long startTime;

    private void touchDown(MotionEvent event) {
    
    
        startTime = SystemClock.elapsedRealtime();
        float x = event.getX();
        float y = event.getY();
        mX = x;
        mY = y;
        // mPath绘制的绘制起点
        mPath.moveTo(x, y);
    }

    // 手指在屏幕上滑动时调用
    private void touchMove(MotionEvent event) {
    
    
        final float x = event.getX();
        final float y = event.getY();
        final float previousX = mX;
        final float previousY = mY;
        final float dx = Math.abs(x - previousX);
        final float dy = Math.abs(y - previousY);
        // 两点之间的距离大于等于3时,生成贝塞尔绘制曲线
        if (dx >= 3 || dy >= 3) {
    
    
            // 设置贝塞尔曲线的操作点为起点和终点的一半
            float cX = (x + previousX) / 2;
            float cY = (y + previousY) / 2;
            // 二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点
            mPath.quadTo(previousX, previousY, cX, cY);
            // 第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值
            mX = x;
            mY = y;
        }
    }

    /**
     * 清除画板
     */
    public void clear() {
    
    
        if (cacheCanvas != null) {
    
    
            //更新画板信息
            mGesturePaint.setColor(mPenColor);
            cacheCanvas.drawColor(mBackColor, PorterDuff.Mode.CLEAR);
            mGesturePaint.setColor(mPenColor);
            invalidate();
        }
    }


    /**
     * 保存画板
     *
     * @param path 保存到路径
     */
    public void save(String path) throws IOException {
    
    
        save(path, false, 0);
    }

    public void setMakeImage() {
    
    
        if (isDown) {
    
    
            cachebBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            cacheCanvas = new Canvas(cachebBitmap);
            cacheCanvas.drawColor(mBackColor);
            cacheCanvas.drawPath(mPath, mGesturePaint);
            if (signatureCallBack != null) {
    
    
                Log.e("TAG", "finish");
                Bitmap b = clearBlank(cachebBitmap, 0);
                Log.e("TAG", "finish b-->" + b);
                if (b == null) {
    
    
                    clear();
                }
                signatureCallBack.onSignCompeleted(SignatureView.this, clearBlank(cachebBitmap, 0));
            }
            mPath.reset();
            invalidate();
        }
    }

    /**
     * 保存画板
     *
     * @param path       保存到路径
     * @param clearBlank 是否清除边缘空白区域
     * @param blank      要保留的边缘空白距离
     */
    public void save(String path, boolean clearBlank, int blank) throws IOException {
    
    

        Bitmap bitmap = cachebBitmap;
        //BitmapUtil.createScaledBitmapByHeight(srcBitmap, 300);//  压缩图片
        if (clearBlank) {
    
    
            bitmap = clearBlank(bitmap, blank);
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
        byte[] buffer = bos.toByteArray();
        if (buffer != null) {
    
    
            File file = new File(path);
            if (file.exists()) {
    
    
                file.delete();
            }
            OutputStream outputStream = new FileOutputStream(file);
            outputStream.write(buffer);
            outputStream.close();
        }
    }

    /**
     * 获取画板的bitmap
     *
     * @return
     */
    public Bitmap getBitMap() {
    
    
        setDrawingCacheEnabled(true);
        buildDrawingCache();
        Bitmap bitmap = getDrawingCache();
        setDrawingCacheEnabled(false);
        return bitmap;
    }

    /**
     * 逐行扫描 清楚边界空白。
     *
     * @param bp
     * @param blank 边距留多少个像素
     * @return
     */
    private Bitmap clearBlank(Bitmap bp, int blank) {
    
    
        try {
    
    
            int HEIGHT = bp.getHeight();
            int WIDTH = bp.getWidth();
            int top = 0, left = 0, right = 0, bottom = 0;
            int[] pixs = new int[WIDTH];
            boolean isStop;
            for (int y = 0; y < HEIGHT; y++) {
    
    
                bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
                isStop = false;
                for (int pix : pixs) {
    
    
                    if (pix != mBackColor) {
    
    
                        top = y;
                        isStop = true;
                        break;
                    }
                }
                if (isStop) {
    
    
                    break;
                }
            }
            for (int y = HEIGHT - 1; y >= 0; y--) {
    
    
                bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
                isStop = false;
                for (int pix : pixs) {
    
    
                    if (pix != mBackColor) {
    
    
                        bottom = y;
                        isStop = true;
                        break;
                    }
                }
                if (isStop) {
    
    
                    break;
                }
            }
            pixs = new int[HEIGHT];
            for (int x = 0; x < WIDTH; x++) {
    
    
                bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
                isStop = false;
                for (int pix : pixs) {
    
    
                    if (pix != mBackColor) {
    
    
                        left = x;
                        isStop = true;
                        break;
                    }
                }
                if (isStop) {
    
    
                    break;
                }
            }
            for (int x = WIDTH - 1; x > 0; x--) {
    
    
                bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
                isStop = false;
                for (int pix : pixs) {
    
    
                    if (pix != mBackColor) {
    
    
                        right = x;
                        isStop = true;
                        break;
                    }
                }
                if (isStop) {
    
    
                    break;
                }
            }
            if (blank < 0) {
    
    
                blank = 0;
            }
            left = left - blank > 0 ? left - blank : 0;
            top = top - blank > 0 ? top - blank : 0;
            right = right + blank > WIDTH - 1 ? WIDTH - 1 : right + blank;
            bottom = bottom + blank > HEIGHT - 1 ? HEIGHT - 1 : bottom + blank;
            Bitmap b = Bitmap.createBitmap(bp, left, top, (right - left), (bottom - top));
            int resultW = b.getWidth() * targetHeight / b.getHeight();
            return Bitmap.createScaledBitmap(b, resultW, targetHeight, false);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    public interface ISignatureCallBack {
    
    
        void onSignCompeleted(View view, Bitmap bitmap);
    }
}

2.xml文件中使用:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!--引入画板-->
    <com.example.administrator.xingtest.SignatureView
        android:id="@+id/view_signature"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="60dp"
        app:penColor="#000"
        app:penWidth="10"
        app:backColor="#fff" />

    <View
        android:layout_alignBottom="@id/view_signature"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="#000"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true">

        <Button
            android:id="@+id/btn_clear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清除"
            android:layout_marginLeft="30dp"
            />

        <Button
            android:id="@+id/btn_save"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="保存"
            android:layout_marginRight="30dp"
            />
    </RelativeLayout>


</RelativeLayout>

在这里插入图片描述

3.Activity中使用:

public class MainActivity extends AppCompatActivity {
    
    

    private Button btnClear;
    private Button btnSave;
    private SignatureView viewSignature;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initVIew();
    }

    private void initVIew(){
    
    
        btnClear = (Button) findViewById(R.id.btn_clear);
        btnSave = (Button) findViewById(R.id.btn_save);
        viewSignature = (SignatureView) findViewById(R.id.view_signature);

        btnClear.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                //清空画笔
                viewSignature.clear();
            }
        });

        btnSave.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
        
                if (viewSignature.getTouched()) {
    
    
                    try {
    
    
                        viewSignature.save("/sdcard/sign.png", true, 10);
                        Toast.makeText(MainActivity.this, "图片保存在:"+viewSignature.getSavePath(), Toast.LENGTH_SHORT).show();
                    } catch (IOException e) {
    
    
                        e.printStackTrace();
                    }
                } else {
    
    
                    Toast.makeText(MainActivity.this, "请先签名", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

在这里插入图片描述

4.attrs.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SignatureView">
        <attr format="color" name="penColor"/>
        <attr format="color" name="backColor"/>
        <attr format="integer" name="penWidth"/>
    </declare-styleable>
</resources>

5.AndroidManifest.xml 添加写权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

猜你喜欢

转载自blog.csdn.net/qq_30297763/article/details/107844281