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

public class SignatureView extends View {

// View state

private List mPoints;

private boolean mIsEmpty;

private float mLastTouchX;

private float mLastTouchY;

private float mLastVelocity;

private float mLastWidth;

private RectF mDirtyRect;

// Configurable parameters

private int mMinWidth;

private int mMaxWidth;

private float mVelocityFilterWeight;

private OnSignedListener mOnSignedListener;

private Paint mPaint = new Paint();

private Path mPath = new Path();

private Bitmap mSignatureBitmap = null;

private Canvas mSignatureBitmapCanvas = null;

public SignatureView(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SignatureView, 0, 0);

// Configurable parameters

try {

mMinWidth = a.getDimensionPixelSize(R.styleable.SignatureView_minWidth, convertDpToPx(3));

mMaxWidth = a.getDimensionPixelSize(R.styleable.SignatureView_maxWidth, convertDpToPx(7));

mVelocityFilterWeight = a.getFloat(R.styleable.SignatureView_velocityFilterWeight, 0.9f);

mPaint.setColor(a.getColor(R.styleable.SignatureView_penColor, Color.BLACK));

} finally {

a.recycle();

}

// Fixed parameters

mPaint.setAntiAlias(true);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeCap(Paint.Cap.ROUND);

mPaint.setStrokeJoin(Paint.Join.ROUND);

// Dirty rectangle to update only the changed portion of the view

mDirtyRect = new RectF();

clear();

}

/**

  • Set the pen color from a given resource. If the resource is not found,

  • {@link android.graphics.Color#BLACK} is assumed.

  • @param colorRes

  •        the color resource.
    

*/

public void setPenColorRes(int colorRes) {

try {

setPenColor(getResources().getColor(colorRes));

} catch (Resources.NotFoundException ex) {

setPenColor(getResources().getColor(Color.BLACK));

}

}

/**

  • Set the pen color from a given color.

  • @param color

  •        the color.
    

*/

public void setPenColor(int color) {

mPaint.setColor(color);

}

/**

  • Set the minimum width of the stroke in pixel.

  • @param minWidth

  •        the width in dp.
    

*/

public void setMinWidth(float minWidth) {

mMinWidth = convertDpToPx(minWidth);

}

/**

  • Set the maximum width of the stroke in pixel.

  • @param maxWidth

  •        the width in dp.
    

*/

public void setMaxWidth(float maxWidth) {

mMaxWidth = convertDpToPx(maxWidth);

}

/**

  • Set the velocity filter weight.

  • @param velocityFilterWeight

  •        the weight.
    

*/

public void setVelocityFilterWeight(float velocityFilterWeight) {

mVelocityFilterWeight = velocityFilterWeight;

}

public void clear() {

mPoints = new ArrayList();

mLastVelocity = 0;

mLastWidth = (mMinWidth + mMaxWidth) / 2;

mPath.reset();

if (mSignatureBitmap != null) {

mSignatureBitmap = null;

ensureSignatureBitmap();

}

setIsEmpty(true);

invalidate();

}

@Override

public boolean onTouchEvent(MotionEvent event) {

if (!isEnabled())

return false;

float eventX = event.getX();

float eventY = event.getY();

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

getParent().requestDisallowInterceptTouchEvent(true);

mPoints.clear();

mPath.moveTo(eventX, eventY);

mLastTouchX = eventX;

mLastTouchY = eventY;

addPoint(new TimedPoint(eventX, eventY));

case MotionEvent.ACTION_MOVE:

resetDirtyRect(eventX, eventY);

addPoint(new TimedPoint(eventX, eventY));

break;

case MotionEvent.ACTION_UP:

resetDirtyRect(eventX, eventY);

addPoint(new TimedPoint(eventX, eventY));

getParent().requestDisallowInterceptTouchEvent(true);

setIsEmpty(false);

break;

default:

return false;

}

// invalidate();

invalidate((int) (mDirtyRect.left - mMaxWidth), (int) (mDirtyRect.top - mMaxWidth),

(int) (mDirtyRect.right + mMaxWidth), (int) (mDirtyRect.bottom + mMaxWidth));

return true;

}

@Override

protected void onDraw(Canvas canvas) {

if (mSignatureBitmap != null) {

canvas.drawBitmap(mSignatureBitmap, 0, 0, mPaint);

}

}

public void setOnSignedListener(OnSignedListener listener) {

mOnSignedListener = listener;

}

public boolean isEmpty() {

return mIsEmpty;

}

public Bitmap getSignatureBitmap() {

Bitmap originalBitmap = getTransparentSignatureBitmap();

Bitmap whiteBgBitmap = Bitmap.createBitmap(originalBitmap.getWidth(), originalBitmap.getHeight(),

Bitmap.Config.ARGB_8888);

Canvas canvas = new Canvas(whiteBgBitmap);

canvas.drawColor(Color.WHITE);

canvas.drawBitmap(originalBitmap, 0, 0, null);

return whiteBgBitmap;

}

public void setSignatureBitmap(Bitmap signature) {

clear();

ensureSignatureBitmap();

RectF tempSrc = new RectF();

RectF tempDst = new RectF();

int dWidth = signature.getWidth();

int dHeight = signature.getHeight();

int vWidth = getWidth();

int vHeight = getHeight();

// Generate the required transform.

tempSrc.set(0, 0, dWidth, dHeight);

tempDst.set(0, 0, vWidth, vHeight);

Matrix drawMatrix = new Matrix();

drawMatrix.setRectToRect(tempSrc, tempDst, Matrix.ScaleToFit.CENTER);

Canvas canvas = new Canvas(mSignatureBitmap);

canvas.drawBitmap(signature, drawMatrix, null);

setIsEmpty(false);

invalidate();

}

public Bitmap getTransparentSignatureBitmap() {

ensureSignatureBitmap();

return mSignatureBitmap;

}

public Bitmap getTransparentSignatureBitmap(boolean trimBlankSpace) {

if (!trimBlankSpace) {

return getTransparentSignatureBitmap();

}

ensureSignatureBitmap();

int imgHeight = mSignatureBitmap.getHeight();

int imgWidth = mSignatureBitmap.getWidth();

int backgroundColor = Color.TRANSPARENT;

int xMin = Integer.MAX_VALUE, xMax = Integer.MIN_VALUE, yMin = Integer.MAX_VALUE, yMax = Integer.MIN_VALUE;

boolean foundPixel = false;

// Find xMin

for (int x = 0; x < imgWidth; x++) {

boolean stop = false;

for (int y = 0; y < imgHeight; y++) {

if (mSignatureBitmap.getPixel(x, y) != backgroundColor) {

xMin = x;

stop = true;

foundPixel = true;

break;

}

}

if (stop)

break;

}

// Image is empty…

if (!foundPixel)

return null;

// Find yMin

for (int y = 0; y < imgHeight; y++) {

boolean stop = false;

for (int x = xMin; x < imgWidth; x++) {

if (mSignatureBitmap.getPixel(x, y) != backgroundColor) {

yMin = y;

stop = true;

break;

}

}

if (stop)

break;

}

// Find xMax

for (int x = imgWidth - 1; x >= xMin; x–) {

boolean stop = false;

for (int y = yMin; y < imgHeight; y++) {

if (mSignatureBitmap.getPixel(x, y) != backgroundColor) {

xMax = x;

stop = true;

break;

}

}

if (stop)

break;

}

// Find yMax

for (int y = imgHeight - 1; y >= yMin; y–) {

boolean stop = false;

for (int x = xMin; x <= xMax; x++) {

if (mSignatureBitmap.getPixel(x, y) != backgroundColor) {

yMax = y;

stop = true;

break;

}

}

if (stop)

break;

}

return Bitmap.createBitmap(mSignatureBitmap, xMin, yMin, xMax - xMin, yMax - yMin);

}

private void addPoint(TimedPoint newPoint) {

mPoints.add(newPoint);

if (mPoints.size() > 2) {

// To reduce the initial lag make it work with 3 mPoints

// by copying the first point to the beginning.

if (mPoints.size() == 3)

mPoints.add(0, mPoints.get(0));

ControlTimedPoints tmp = calculateCurveControlPoints(mPoints.get(0), mPoints.get(1), mPoints.get(2));

TimedPoint c2 = tmp.c2;

tmp = calculateCurveControlPoints(mPoints.get(1), mPoints.get(2), mPoints.get(3));

TimedPoint c3 = tmp.c1;

Bezier curve = new Bezier(mPoints.get(1), c2, c3, mPoints.get(2));

结尾

最后,针对上面谈的内容,给大家推荐一个Android资料,应该对大家有用。

首先是一个知识清单:(对于现在的Android及移动互联网来说,我们需要掌握的技术)

泛型原理丶反射原理丶Java虚拟机原理丶线程池原理丶
注解原理丶注解原理丶序列化
Activity知识体系(Activity的生命周期丶Activity的任务栈丶Activity的启动模式丶View源码丶Fragment内核相关丶service原理等)
代码框架结构优化(数据结构丶排序算法丶设计模式)
APP性能优化(用户体验优化丶适配丶代码调优)
热修复丶热升级丶Hook技术丶IOC架构设计
NDK(c编程丶C++丶JNI丶LINUX)
如何提高开发效率?
MVC丶MVP丶MVVM
微信小程序
Hybrid
Flutter

接下来是资料清单:(敲黑板!!!


1.数据结构和算法

2.设计模式

3.全套体系化高级架构视频;七大主流技术模块,视频+源码+笔记

4.面试专题资料包(怎么能少了一份全面的面试题总结呢~)

不论遇到什么困难,都不应该成为我们放弃的理由!共勉~

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
热修复丶热升级丶Hook技术丶IOC架构设计

NDK(c编程丶C++丶JNI丶LINUX)
如何提高开发效率?
MVC丶MVP丶MVVM
微信小程序
Hybrid
Flutter

[外链图片转存中…(img-AH9sKtfb-1725663885117)]

接下来是资料清单:(敲黑板!!!


1.数据结构和算法

[外链图片转存中…(img-qwdoHM35-1725663885117)]

2.设计模式

[外链图片转存中…(img-gnGpcuyz-1725663885118)]

3.全套体系化高级架构视频;七大主流技术模块,视频+源码+笔记

[外链图片转存中…(img-u909nnNm-1725663885118)]

4.面试专题资料包(怎么能少了一份全面的面试题总结呢~)

[外链图片转存中…(img-EEQtBJAV-1725663885118)]

不论遇到什么困难,都不应该成为我们放弃的理由!共勉~

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

[外链图片转存中…(img-43coDGbY-1725663885119)]

加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值