本文主要介绍Android手写签名的功能实现,效果如下图

1、根据人名的个数绘制人的名称

这个逻辑分几个步骤:首先创建画笔,然后根据一个字,创建一个字的矩形框,然后根据矩形框获取到画这个字的宽高。

//设置抗锯齿mMiPaint.setAntiAlias(true);mMiPaint.setTextSize(strokeWidth);//设置签名笔画样式mMiPaint.setStyle(Paint.Style.FILL);//设置笔画宽度mMiPaint.setStrokeWidth(10);//设置签名颜色mMiPaint.setColor(color);rect = new Rect();//将内容的长和宽。添加到rect矩形中mMiPaint.getTextBounds(test, 0, test.length(), rect);//获取宽mTextWidth = rect.width();mTextHeight = rect.height();

根据人名的个数将控件的宽高分成几个部分,让人的名称居中显示

 private void drawText(Canvas canvas) {String test = "我";//将内容的长和宽。添加到rect矩形中mMiPaint.getTextBounds(test, 0, test.length(), rect);//获取宽mTextWidth = rect.width();mTextHeight = rect.height();mSumWidth = getWidth();mSumHeight = getHeight();if (StringUtils.isEmpty(mText)) {return;}float centerY= mSumHeight / 2;char[] chars = mText.toCharArray();int sum1 = chars.length * 2;for (int i = 0; i < chars.length; i++) {String txt = chars[i] + "";//开始位置int multiple = 2 * i + 1;float x = mSumWidth * multiple / sum1 - mTextWidth / 2;float y = mSumHeight / 2 + mTextHeight / 2;canvas.drawText(txt, x, y, mMiPaint);float centerX = mSumWidth * multiple / sum1;drawDottedLine(centerX, centerY, canvas);}}

2、根据文字画米子格

根据字的中心位置还画米子格

  private void drawDottedLine(float x, float y, Canvas canvas) {float width = mTextWidth * 1.5f;float height = mTextHeight * 1.5f;// 左上至右下线float leftTopLineStartX = x - width / 2;float leftTopLineStartY = y - height / 2;float leftTopLineEndX = x + width / 2;float leftTopLineEndY = y + height / 2;drawDottedLine(leftTopLineStartX, leftTopLineStartY, leftTopLineEndX, leftTopLineEndY, canvas);// 水平线float horizontalLineStartX = leftTopLineStartX;float horizontalLineStartY = leftTopLineStartY + height / 2;float horizontalLineEndX = horizontalLineStartX + width;float horizontalLineEndY = horizontalLineStartY;drawDottedLine(horizontalLineStartX, horizontalLineStartY, horizontalLineEndX, horizontalLineEndY, canvas);// 右下至左上float lowerRightLineStartX = leftTopLineStartX;float lowerRightLineStartY = leftTopLineEndY;float lowerRightLineEndX = lowerRightLineStartX + width;float lowerRightLineEndY = leftTopLineStartY;drawDottedLine(lowerRightLineStartX, lowerRightLineStartY, lowerRightLineEndX, lowerRightLineEndY, canvas);// 纵向线float verticalLineStartX = leftTopLineStartX + width / 2;float verticalLineStartY = leftTopLineStartY;float verticalLineEndX = verticalLineStartX;float verticalLineEndY = leftTopLineStartY + height;drawDottedLine(verticalLineStartX, verticalLineStartY, verticalLineEndX,verticalLineEndY, canvas);}
 private void drawDottedLine(float startX, float startY, float endX, float endY, Canvas canvas) {Path path = new Path();path.moveTo(startX, startY);path.lineTo(endX, endY);canvas.drawPath(path, mDottedLinePaint);}

完整的代码如下:

package com.iflyrec.modulesignin.view;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.ColorInt;
import com.iflyrec.modulebase.util.StringUtils;
import com.iflyrec.modulesignin.R;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class LinePathView extends View {private static final String TAG = "LinePathView";private Context mContext;//起点Xprivate float mX;//起点Yprivate float mY;//手写画笔private final Paint mGesturePaint = new Paint();//画米字格的画笔private final Paint mMiPaint = new Paint();//画虚线private final Paint mDottedLinePaint = 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.TRANSPARENT;//文字private String mText;//获取一个字宽float mTextWidth;//获取一个字高float mTextHeight;//控件的宽度float mSumWidth;//控件的高度float mSumHeight;public LinePathView(Context context) {super(context);init(context);}public LinePathView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public LinePathView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context) {this.mContext = context;//设置抗锯齿mGesturePaint.setAntiAlias(true);//设置签名笔画样式mGesturePaint.setStyle(Paint.Style.STROKE);mGesturePaint.setStrokeCap(Paint.Cap.ROUND);//设置笔画宽度mGesturePaint.setStrokeWidth(mPaintWidth);//设置签名颜色mGesturePaint.setColor(mPenColor);initMi();initDottedLine();}Rect rect;private void initMi() {int color = mContext.getColor(R.color.color_179098A9);int strokeWidth = (int) mContext.getResources().getDimension(R.dimen.qb_px_152);//设置抗锯齿mMiPaint.setAntiAlias(true);mMiPaint.setTextSize(strokeWidth);//设置签名笔画样式mMiPaint.setStyle(Paint.Style.FILL);
//        mMiPaint.setStrokeCap(Paint.Cap.ROUND);//设置笔画宽度mMiPaint.setStrokeWidth(10);//设置签名颜色mMiPaint.setColor(color);rect = new Rect();}//画虚线private void initDottedLine() {int color = mContext.getColor(R.color.color_339098A9);mDottedLinePaint.setStyle(Paint.Style.STROKE);mDottedLinePaint.setAntiAlias(true);mDottedLinePaint.setStrokeWidth(2);mDottedLinePaint.setColor(color);mDottedLinePaint.setPathEffect(new DashPathEffect(new float[]{4, 4}, 0));}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//创建跟view一样大的bitmap,用来保存签名(在控件大小发生改变时调用。)cachebBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);cacheCanvas = new Canvas(cachebBitmap);cacheCanvas.drawColor(mBackColor);drawText(cacheCanvas);}private void drawText(Canvas canvas) {String test = "我";//将内容的长和宽。添加到rect矩形中mMiPaint.getTextBounds(test, 0, test.length(), rect);//获取宽mTextWidth = rect.width();mTextHeight = rect.height();mSumWidth = getWidth();mSumHeight = getHeight();if (StringUtils.isEmpty(mText)) {return;}float centerY= mSumHeight / 2;char[] chars = mText.toCharArray();int sum1 = chars.length * 2;for (int i = 0; i < chars.length; i++) {String txt = chars[i] + "";//开始位置int multiple = 2 * i + 1;float x = mSumWidth * multiple / sum1 - mTextWidth / 2;float y = mSumHeight / 2 + mTextHeight / 2;canvas.drawText(txt, x, y, mMiPaint);float centerX = mSumWidth * multiple / sum1;drawDottedLine(centerX, centerY, canvas);}}/*** 字的开始位置* @param x* @param y* @param canvas*/private void drawDottedLine(float x, float y, Canvas canvas) {float width = mTextWidth * 1.5f;float height = mTextHeight * 1.5f;// 左上至右下线float leftTopLineStartX = x - width / 2;float leftTopLineStartY = y - height / 2;float leftTopLineEndX = x + width / 2;float leftTopLineEndY = y + height / 2;drawDottedLine(leftTopLineStartX, leftTopLineStartY, leftTopLineEndX, leftTopLineEndY, canvas);// 水平线float horizontalLineStartX = leftTopLineStartX;float horizontalLineStartY = leftTopLineStartY + height / 2;float horizontalLineEndX = horizontalLineStartX + width;float horizontalLineEndY = horizontalLineStartY;drawDottedLine(horizontalLineStartX, horizontalLineStartY, horizontalLineEndX, horizontalLineEndY, canvas);// 右下至左上float lowerRightLineStartX = leftTopLineStartX;float lowerRightLineStartY = leftTopLineEndY;float lowerRightLineEndX = lowerRightLineStartX + width;float lowerRightLineEndY = leftTopLineStartY;drawDottedLine(lowerRightLineStartX, lowerRightLineStartY, lowerRightLineEndX, lowerRightLineEndY, canvas);// 纵向线float verticalLineStartX = leftTopLineStartX + width / 2;float verticalLineStartY = leftTopLineStartY;float verticalLineEndX = verticalLineStartX;float verticalLineEndY = leftTopLineStartY + height;drawDottedLine(verticalLineStartX, verticalLineStartY, verticalLineEndX,verticalLineEndY, canvas);}private void drawDottedLine(float startX, float startY, float endX, float endY, Canvas canvas) {Path path = new Path();path.moveTo(startX, startY);path.lineTo(endX, endY);canvas.drawPath(path, mDottedLinePaint);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//画此次笔画之前的签名canvas.drawBitmap(cachebBitmap, 0, 0, mGesturePaint);// 通过画布绘制多点形成的图形canvas.drawPath(mPath, mGesturePaint);}@Overridepublic 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://将路径画到bitmap中,即一次笔画完成才去更新bitmap,而手势轨迹是实时显示在画板上的。cacheCanvas.drawPath(mPath, mGesturePaint);mPath.reset();break;}// 更新绘制invalidate();return true;}// 手指点下屏幕时调用private void touchDown(MotionEvent event) {// 重置绘制路线mPath.reset();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);mGesturePaint.setColor(mPenColor);drawText(cacheCanvas);invalidate();}}/*** 保存画板** @param path 保存到路径*/public void save(String path) throws IOException {save(path, false, 0);}/*** 保存画板** @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();}}/*** 保存画板** @param clearBlank 是否清除边缘空白区域* @param blank      要保留的边缘空白距离*/public Bitmap saveToBitmap(boolean clearBlank, int blank) {Bitmap bitmap = cachebBitmap;//BitmapUtil.createScaledBitmapByHeight(srcBitmap, 300);//  压缩图片if (clearBlank) {bitmap = clearBlank(bitmap, blank);}
//        int width = bitmap.getWidth();
//        int height = bitmap.getHeight();
//        int w;
//        int h;
//        if(width>2*height){//            w = width -(width - 2*height);
//            h = height;
//        } else {//            w = width;
//            h = height - (height - width/2);
//        }
//        return ThumbnailUtils.extractThumbnail(bitmap,w,h);return bitmap;}/*** 获取画板的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) {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;left = Math.max(left - blank, 0);top = Math.max(top - blank, 0);right = Math.min(right + blank, WIDTH - 1);bottom = Math.min(bottom + blank, HEIGHT - 1);//防止创建null的bitmap  引发的崩溃if (left == 0 && top == 0 && right == 0 && bottom == 0) {left = 1;top = 1;right = 351;bottom = 251;}return Bitmap.createBitmap(bp, left, top, right - left, bottom - top);}/*** 设置画笔宽度 默认宽度为10px** @param mPaintWidth*/public void setPaintWidth(int mPaintWidth) {mPaintWidth = mPaintWidth > 0 ? mPaintWidth : 10;this.mPaintWidth = mPaintWidth;mGesturePaint.setStrokeWidth(mPaintWidth);}public void setBackColor(@ColorInt int backColor) {mBackColor = backColor;}/*** 设置画笔颜色** @param mPenColor*/public void setPenColor(int mPenColor) {this.mPenColor = mPenColor;mGesturePaint.setColor(mPenColor);}public void setText(String str) {this.mText = str;}
}

使用示例

布局文件

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

在界面直接设置就可以了

mPathView = findViewById(R.id.linePathView);
mPathView.setBackColor(getColor(R.color.color_F6F9FC));
mPathView.setPenColor(getColor(R.color.color_000000));
mPathView.setText(str);

参考

https://www.jianshu.com/p/e6524bb457f7

Android手写签名功能(包含画米字格,人名和书写轨迹)相关推荐

  1. android 手写签批_Android自定义实现手写签名功能

    一.Android自定义View步骤 : 自定义属性: 选择和设置构造方法: 重写onMeasure()方法: 重写onDraw()方法: 重写onLayout()方法: 重写其他事件的方法(滑动监听 ...

  2. android 电子签名 手写签名 功能实现

    android 电子签名  手写签名 功能实现 这个手写的效果 就是一个 重写的的自定义的view  代码如下: package com.example.hand.views;import java. ...

  3. Android手写签名 附带背景图设置

    android手写签名的demo网上其实有很多,但是大多没考虑到签名用在哪里的问题,所以就需要背景图设置,保存电子签名的时候  会连同背景图一起保存   这才达到了电子签名的效果,背景可以放置合同,请 ...

  4. android 手写签名

    Android 手写签名是指使用手指在 Android 设备上绘制的签名.它通常用于数字签名或签署电子文件.可以通过使用手写输入 API 和触摸事件 API 来实现手写签名功能.这可以通过开发自定义视 ...

  5. Android手写签名

    手写签名自定义实现,看注释就行了 package com.zhuzi.taobamboo.user_defined; import android.content.Context; import an ...

  6. Android 手写签名实例

    这篇文章本来想在一个月前就发布的,最近一直忙于国家电网手持终端的应用开发,所以没抽出时间来写.周末到了,终于可以闲下来整理整理.话不多说,直奔主题. Android 提供了很多丰富.实用而且很有特色的 ...

  7. html5 移动端手写签名,H5移动端项目实现手写签名功能 vue实现手写签名

    vue 移动端实现手写签名效果,功能很完美,保存时保存为base64格式. 刚好项目用到此功能,就网上找了一下,清理了无用代码,简单方便,因为项目中多个地方需要使用,所以我将它整理为组件,通过ref和 ...

  8. H5移动端项目实现手写签名功能 vue实现手写签名

    vue 移动端实现手写签名效果,功能很完美,保存时保存为base64格式. base64转file文件格式 vue中将base64转file文件格式 刚好项目用到此功能,就网上找了一下,清理了无用代码 ...

  9. vue canvas 方法无效_vue实现手机app手写签名功能

    我曾经在一个文书交互相关的项目中遇到过这样的一个需求,当用户接收到管理员发送的文书时,用户需要在这个文书上签字签收,签名需要跟原有的文书进行合并,做到模仿线下真实签收的电子签名.这签收没有调用APP特 ...

最新文章

  1. Eclipse中JVM内存设置
  2. Go程序性能分析pprof
  3. java9 opens与exports的区别
  4. 扎实的基础是成功的法宝
  5. dict下如何取值_年薪百万之路--第十七天 装饰器(下)和迭代器
  6. ubuntu镜像添加jdk_docker基础镜像ubuntu添加jdk1.8
  7. 两个rpm文件包存在互相依赖关系时,需要同时安装,解决办法如下
  8. js 中实现 汉字按拼音排序
  9. UML概要基础知识(待完善)
  10. C# 计算农历日期方法(2021版)
  11. 无法直接打开jar文件,提示“你要以何种方式打开.jar文件”(已解决)
  12. DBA_实践指南系列9_Oracle Erp R12应用补丁AutoPatch/AutoControl/AutoConfig(案例)
  13. 写给大学男同胞几条择偶建议
  14. javafx 教程_集成JavaFX和Swing
  15. ATECC508A芯片开发笔记(一):初识加密芯片
  16. Pytorch实现Deep Mutual Learning网络
  17. 程序人生-哈工大计算机系统大作业2022春
  18. 单片机毕业设计 stm32火灾报警系统
  19. 进厂都要去越南,富士康“曲线救国”,计划增加越南员工人数
  20. CISP知识思维导图

热门文章

  1. 爱家Aijiacms高端大型房产门户系统V9源码+带手机端
  2. linux下载百度命令行,Linux 命令行使用百度网盘上传下载文件
  3. SAP QM初阶之事务代码QC51为采购订单创建Quality Certificate
  4. 数据库 day60,61 Oracle入门,单行函数,多表查询,子查询,事物处理,约束,rownum分页,视图,序列,索引
  5. vue自定义指令 v-focus 实现
  6. INSPIRED启示录 读书笔记 - 第17章 产品人物角色
  7. linux下微信/qq的aud、silk音频文件格式与mp3格式互转,获取音频时长的方法,附问题分析和java代码。
  8. 天正加载时在tshowbar卡死的解决方案
  9. 图文详解 HBase 的读写流程
  10. 贵阳个税系统代理服务器地址,贵阳金三个税服务器地址