ps:因公司推崇线上信息办公化 设计到客户签名 将客户签好的名字上传到服务器 因此 写了一个demo
废话不多哔哔 上效果图:

这里我运用的是自定义view

//权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
public class SignatureView extends View {    private static final String TAG = SignatureView.class.getSimpleName();    public static final int PEN_WIDTH = 10;    public static final int PEN_COLOR = Color.BLACK;    public static final int BACK_COLOR = Color.WHITE;    //画笔x坐标起点    private float mPenX;    //画笔y坐标起点    private float mPenY;    private Paint mPaint = new Paint();    private Path mPath = new Path();    private Canvas mCanvas;    private Bitmap cacheBitmap;    //画笔宽度    private int mPentWidth = PEN_WIDTH;    //画笔颜色    private int mPenColor = PEN_COLOR;    //画板颜色    private int mBackColor = BACK_COLOR;    private boolean isTouched = false;    private String mSavePath = null;    public SignatureView(Context context) {        this(context, null);    }    public SignatureView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SignatureView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SignatureView);//拿到样式集合        //画笔颜色        mPenColor = typedArray.getColor(R.styleable.SignatureView_penColor, PEN_COLOR);        //画板颜色        mBackColor = typedArray.getColor(R.styleable.SignatureView_backColor, BACK_COLOR);        //画笔宽度        mPentWidth = typedArray.getInt(R.styleable.SignatureView_penWidth, PEN_WIDTH);        typedArray.recycle();//回收资源        init();    }    private void init() {        mPaint.setAntiAlias(true);//抗锯齿        mPaint.setStyle(Paint.Style.STROKE);//描边        mPaint.setStrokeWidth(mPentWidth);//设置画笔宽度        mPaint.setColor(mPenColor); //设置画笔颜色  black    }    public boolean getTouched() {        return isTouched;    }    public void setPentWidth(int pentWidth) {        mPentWidth = pentWidth;    }    public void setPenColor(@ColorInt int penColor) {        mPenColor = penColor;    }    public void setBackColor(@ColorInt int backColor) {        mBackColor = backColor;    }    /**     * 清空签名     */    public void clear() {        if (mCanvas != null) {            isTouched = false;            mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//清除画布内容            mCanvas.drawColor(mBackColor);//重新设置画布颜色            invalidate();        }    }    /**     * 保存图片     *     * @param path 保存的地址     * @param clearBlank 是否清除空白区域     * @param blank 空白区域留空距离     * @throws IOException     */    public void save(String path, boolean clearBlank, int blank,Context context) throws IOException {        if (TextUtils.isEmpty(path)) {            return;        }        mSavePath = path;        Bitmap bitmap = cacheBitmap;        Log.i("zahuishi","@"+bitmap);        saveFile(context,bitmap);//        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 os = new FileOutputStream(file);//            os.write(buffer);//            os.close();//            bos.close();//        }    }    public static void saveFile(Context context, Bitmap bm) throws IOException {        File dirFile = new File(Environment.getExternalStorageDirectory().getPath());        if (!dirFile.exists()) {            dirFile.mkdir();        }        String fileName = UUID.randomUUID().toString() + ".jpg";        File myCaptureFile = new File(Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/" + fileName);        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));        bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);        bos.flush();        bos.close();        //把图片保存后声明这个广播事件通知系统相册有新图片到来        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);        Uri uri = Uri.fromFile(myCaptureFile);        intent.setData(uri);        context.sendBroadcast(intent);    }    /**     * 获取Bitmap缓存     */    public Bitmap getBitmap() {        setDrawingCacheEnabled(true);        buildDrawingCache();        Bitmap bitmap = getDrawingCache();        setDrawingCacheEnabled(false);        return bitmap;    }    /**     * 获取保存路径     */    public String getSavePath() {        return mSavePath;    }    /**     * 逐行扫描,清除边界空白     *     * @param blank 边界留多少个像素     */    private Bitmap clearBlank(Bitmap bmp, int blank) {        int height = bmp.getHeight();        int width = bmp.getWidth();        int top = 0, left = 0, right = 0, bottom = 0;        int[] pixs = new int[width];        boolean isStop;        //扫描上边距不等于背景颜色的第一个点        for (int i = 0; i < height; i++) {            bmp.getPixels(pixs, 0, width, 0, i, width, 1);            isStop = false;            for (int pix :                pixs) {                if (pix != mBackColor) {                    top = i;                    isStop = true;                    break;                }            }            if (isStop) {                break;            }        }        //扫描下边距不等于背景颜色的第一个点        for (int i = height - 1; i >= 0; i--) {            bmp.getPixels(pixs, 0, width, 0, i, width, 1);            isStop = false;            for (int pix :                pixs) {                if (pix != mBackColor) {                    bottom = i;                    isStop = true;                    break;                }            }            if (isStop) {                break;            }        }        pixs = new int[height];        //扫描左边距不等于背景颜色的第一个点        for (int x = 0; x < width; x++) {            bmp.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--) {            bmp.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;        return Bitmap.createBitmap(bmp, left, top, right - left, bottom - top);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {//布局发生变化  重新回去控件大小        super.onSizeChanged(w, h, oldw, oldh);        //创建一个空位图,没有色彩,宽高和bitmap2一样        cacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);        //用来承载画的内容。        mCanvas = new Canvas(cacheBitmap);        //画板颜色        mCanvas.drawColor(mBackColor);        isTouched = false;    }    @Override    protected void onDraw(Canvas canvas) {//绘制        super.onDraw(canvas);        canvas.drawBitmap(cacheBitmap, 0, 0, mPaint);        canvas.drawPath(mPath, mPaint);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                mPenX = event.getX();                mPenY = event.getY();                mPath.moveTo(mPenX, mPenY);//不会进行绘制,只用于移动移动画笔。                return true;            case MotionEvent.ACTION_MOVE:                isTouched = true;                float x = event.getX();                float y = event.getY();                float penX = mPenX;                float penY = mPenY;                float dx = Math.abs(x - penX);//取绝对值                float dy = Math.abs(y - penY);                if (dx >= 3 || dy >= 3) {                    float cx = (x + penX) / 2;                    float cy = (y + penY) / 2;                    mPath.quadTo(penX, penY, cx, cy);                    mPenX = x;                    mPenY = y;                }                invalidate();                break;            case MotionEvent.ACTION_UP:                mCanvas.drawPath(mPath, mPaint);                mPath.reset();//清除之前绘制的path                break;            default:                break;        }        return super.onTouchEvent(event);    }}

在MainActivity使用

<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout    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="com.f1reking.signatureview_sample.MainActivity"    >    <Button        android:id="@+id/btn_clear"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:text="清除"        app:layout_constraintHorizontal_weight="1"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toLeftOf="@+id/btn_save"        tools:ignore="MissingConstraints" />    <Button        android:id="@+id/btn_save"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:text="保存"        app:layout_constraintHorizontal_weight="1"        app:layout_constraintLeft_toRightOf="@+id/btn_clear"        app:layout_constraintRight_toRightOf="parent"        tools:ignore="MissingConstraints" />    <com.f1reking.signatureview.SignatureView        android:id="@+id/view_signature"        android:layout_width="match_parent"        android:layout_height="0dp"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintTop_toBottomOf="@+id/btn_clear"        app:layout_constraintVertical_weight="1"        app:backColor="#FFFFFF"        /></androidx.constraintlayout.widget.ConstraintLayout>

主要逻辑代码:

public class MainActivity extends AppCompatActivity {    private static final String TAG ="didijiuwoa" ;    private SignatureView mSignatureView;    private Button btnClear;    private Button btnSave;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        checkPermission();        initView();    }    private void checkPermission() {        //Android平台版本,如我的版本为Android 7.1.2        Log.v(TAG,"Build.VERSION.RELEASE----->"+ Build.VERSION.RELEASE);        //当前手机版本-API版本号        Log.v(TAG,"android.os.Build.VERSION.SDK_INT----->"+Build.VERSION.SDK_INT);        //android 6.0 对应的 API版本号23        Log.v(TAG,"Build.VERSION_CODES.M----->"+Build.VERSION_CODES.M);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//android 6.0以上            Log.v(TAG,"测试手机版本为:android 6.0以上");            int writePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);            if (writePermission != PackageManager.PERMISSION_GRANTED) {                Log.v(TAG,"测试手机版本为:android 6.0以上--->未申请--->申请读写权限");                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);            }else{                Log.v(TAG,"测试手机版本为:android 6.0以上--->已申请");            }        }else{//android 6.0以下            Log.v(TAG,"测试手机版本为:android 6.0以下");        }    }    private void initView() {        mSignatureView = findViewById(R.id.view_signature);        btnClear = findViewById(R.id.btn_clear);        btnSave = findViewById(R.id.btn_save);        btnClear.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mSignatureView.clear();            }        });        btnSave.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {//                Intent intent = new Intent(MainActivity.this,ImageActivity.class);//                startActivity(intent);                if (mSignatureView.getTouched()) {                    try {                        mSignatureView.save("/sdcard/sign.png", true, 10,MainActivity.this);                        Toast.makeText(MainActivity.this, "图片保存在:"+mSignatureView.getSavePath(), Toast.LENGTH_SHORT).show();                    } catch (IOException e) {                        e.printStackTrace();                    }                } else {                    Toast.makeText(MainActivity.this, "请先签名", Toast.LENGTH_SHORT).show();                }            }        });    }    @Override    public void onRequestPermissionsResult(int requestCode,  String[] permissions,  int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        if (requestCode == 100) {            if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE) && grantResults[0]                    == PackageManager.PERMISSION_GRANTED) {//允许                Log.v(TAG, "测试手机版本为:android 6.0以上--->未申请--->申请读写权限--->成功!");            } else {//拒绝                Log.v(TAG, "测试手机版本为:android 6.0以上--->未申请--->申请读写权限--->失败!");                Toast.makeText(this, "请赋予读写权限,否则应用将无法使用!", Toast.LENGTH_LONG).show();                MainActivity.this.finish();            }        }    }}

ok 这就结束了

更多相关文章

  1. 用百度地图API实现Android定位功能(2.6版本为例)
  2. 5.0 导入错误 出现"Loading data for Android(安卓)5.0"
  3. Android-Gradle依赖统一管理
  4. Android(安卓)OpenGL探索之纯色背景绘制
  5. ANDROID 设置状态栏与标题背景颜色一致
  6. 新建Android项目出现错误
  7. android studio3.1.4更新3.2.1版本問題Unknown host 'android-mi
  8. Android(安卓)如何将Canvas上绘制的内容保存成本地图片
  9. Android面试时的问题,实现半透明的popupwindow的源码

随机推荐

  1. Android(安卓)Fragment生命周期——多屏
  2. [视频]Firefox for Android(安卓)预览版
  3. Android网络基础1——网络分层
  4. ym——Android酷炫实用的开源框架(UI框架)(
  5. 【Android】百度地图自定义弹出窗口
  6. Android检测Cursor泄漏的原理以及使用方
  7. android压力测试命令Monkey
  8. 苹果App被置病毒 网友:安卓无压力
  9. Android翻页效果原理实现之翻页的尝试
  10. ANDROID GridView 分页平滑滑动 效果的实