andoird手写签名view

好习惯先来个效果图

在这里插入图片描述

没啥好说的直接上代码

所有的方法都在类内注释的很清楚
直接将他放到layout文件里就行

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

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Stack;

/**
 * 手写签名 主要功能
 * 主要功能:绘制,撤销、清除、颜色、背景、宽度设置,导出文件,导入文件
 * 驰郡
 * wechat:chijun9
 * 2023/11/27
*/
public class SignatureView extends View {
    private Path path; // 用于绘制路径
    private Paint paint; // 用于绘制画笔
    private ArrayList<Path> paths = new ArrayList<>(); // 保存所有路径
    private ArrayList<Paint> paints = new ArrayList<>(); // 保存所有画笔
    private int currentColor = Color.BLACK; // 当前画笔颜色
    private int currentWidth = 5; // 当前画笔宽度
    private Stack<Bitmap> undoStack = new Stack<>(); // 保存撤销的位图
    private Stack<Bitmap> redoStack = new Stack<>(); // 保存重做的位图

    public SignatureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        path = new Path();
        paint = new Paint();
        //设置画笔是否启用抗锯齿效果 用于减少图形边缘的锯齿状失真,使得图形边缘更加平滑
        paint.setAntiAlias(true);
        //设置画笔抖动效果 可以在颜色深度较低的设备上模拟更多的颜色
        paint.setDither(true);
        paint.setColor(currentColor);
        //设置画笔绘制模式 FILL(填充)、STROKE(描边)和FILL_AND_STROKE(填充和描边)。
        paint.setStyle(Paint.Style.STROKE);
        //设置画笔线段连接处样式 MITER(结合处为锐角)、ROUND(结合处为圆弧)和 BEVEL(结合处为直线)
        paint.setStrokeJoin(Paint.Join.ROUND);
        //画笔的线帽指的是线条的两端的样式,可以是BUTT(无线帽)、ROUND(圆线帽)或SQUARE(方线帽)。
        paint.setStrokeCap(Paint.Cap.ROUND);
        //设置画笔绘制线条的宽度 以像素为单位的,默认值是 0
        paint.setStrokeWidth(currentWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < paths.size(); i++) {
            canvas.drawPath(paths.get(i), paints.get(i));
        }
    }



    boolean isUp = true;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 当手指按下时,创建一个新的路径并将其移动到触摸点,将当前路径和画笔添加到列表中,并创建新的路径和画笔
//                path.reset(); // 重置路径

                path = new Path(); // 创建新的路径
                paint = new Paint(); // 创建新的画笔
                //设置画笔是否启用抗锯齿效果 用于减少图形边缘的锯齿状失真,使得图形边缘更加平滑
                paint.setAntiAlias(true);
                //设置画笔抖动效果 可以在颜色深度较低的设备上模拟更多的颜色
                paint.setDither(true);
                paint.setColor(currentColor);
                //设置画笔绘制模式 FILL(填充)、STROKE(描边)和FILL_AND_STROKE(填充和描边)。
                paint.setStyle(Paint.Style.STROKE);
                //设置画笔线段连接处样式 MITER(结合处为锐角)、ROUND(结合处为圆弧)和 BEVEL(结合处为直线)
                paint.setStrokeJoin(Paint.Join.ROUND);
                //画笔的线帽指的是线条的两端的样式,可以是BUTT(无线帽)、ROUND(圆线帽)或SQUARE(方线帽)。
                paint.setStrokeCap(Paint.Cap.ROUND);
                //设置画笔绘制线条的宽度 以像素为单位的,默认值是 0
                paint.setStrokeWidth(currentWidth);
                path.moveTo(x, y); // 将路径移动到触摸点

                if (isUp) {
                    paths.add(path); // 将当前路径添加到路径列表中
                    paints.add(paint); // 将当前画笔添加到画笔列表中
                    isUp = false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                // 当手指移动时,将路径连接到当前触摸点
                path.lineTo(x, y); // 将路径连接到当前触摸点,实现绘制路径
                break;
            case MotionEvent.ACTION_UP:
                isUp = true; //设置当前这段绘制完毕
                break;
            default:
                return false;
        }

        invalidate(); // 请求重绘视图
        return true;
    }

    /**
     * 清除签名
     */
    public void clear() {
        paths.clear();
        paints.clear();
        undoStack.clear();
        redoStack.clear();
        path.reset();
        paint.reset();
        invalidate();
    }

    /**
     * 撤销上一步操作
     */
    public void undo() {
        if (paths.size() > 0) {
            Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            draw(canvas);
            undoStack.push(bitmap);
            paths.remove(paths.size() - 1);
            paints.remove(paints.size() - 1);
            invalidate();
        }
    }

    /**
     * 重做上一步撤销的操作
     */
    public void redo() {
        if (redoStack.size() > 0) {
            Bitmap bitmap = redoStack.pop();
            setSignatureBitmap(bitmap);
        }
    }

    /**
     * 设置画笔颜色
     * @param color 画笔颜色
     */
    public void setColor(int color) {
        currentColor = color;
    }

    /**
     * 验证线宽是否有效
     * @param width 线宽值
     * @return 如果线宽有效则返回true,否则返回false
     */
    private boolean isValidWidth(float width) {
        return width > 0;
    }

    /**
     * 设置画笔宽度
     * @param width 画笔宽度
     */
    public void setWidth(float width) {
        if (!isValidWidth(width)) {
            // 可以在这里添加错误处理逻辑,例如打印错误日志或抛出异常等
            return;
        }
        currentWidth = (int) width;
    }

    /**
     * 改变签名的背景颜色
     * @param color 颜色
     */
    public void setSignatureBackgroundColor(int color) {
        setBackgroundColor(color);
        invalidate(); // 更新视图以显示新的背景颜色设置效果
    }

    /**
     * 获取签名位图
     * @return 签名位图
     */
    public Bitmap getSignatureBitmap() {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        draw(canvas);
        return bitmap;
    }

    /**
     * 设置签名位图
     * @param bitmap 签名位图
     */
    public void setSignatureBitmap(Bitmap bitmap) {
        clear();
        Paint newPaint = new Paint();
        newPaint.setAntiAlias(true);
        newPaint.setDither(true);
        newPaint.setColor(currentColor);
        newPaint.setStyle(Paint.Style.STROKE);
        newPaint.setStrokeJoin(Paint.Join.ROUND);
        newPaint.setStrokeCap(Paint.Cap.ROUND);
        newPaint.setStrokeWidth(currentWidth);
        paths.add(new Path());
        paints.add(newPaint);
        paths.get(0).addPath(path);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        draw(canvas);
        undoStack.push(bitmap);
        invalidate();
    }

    /**
     * 保存签名位图到文件
     * @param filename 文件名
     * @return 是否保存成功
     */
    public boolean saveSignatureToFile(String filename) {
        Bitmap bitmap = getSignatureBitmap();
        try {
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(filename));
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 从文件加载签名位图
     * @param filename 文件名
     * @return 是否加载成功
     */
    public boolean loadSignatureFromFile(String filename) {
        Bitmap bitmap = BitmapFactory.decodeFile(filename);
        if (bitmap != null) {
            setSignatureBitmap(bitmap);
            return true;
        } else {
            return false;
        }
    }
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值