android 电子签名 手写签名 功能实现
【摘要】
android 电子签名 手写签名 功能实现
这个手写的效果 就是一个 重写的的自定义的view 代码如下:
package com.example.hand.views; import java.util.ArrayList;import java.util.List; import a...
android 电子签名 手写签名 功能实现
这个手写的效果 就是一个 重写的的自定义的view 代码如下:
-
package com.example.hand.views;
-
-
import java.util.ArrayList;
-
import java.util.List;
-
-
import android.content.Context;
-
import android.content.res.Resources;
-
import android.content.res.TypedArray;
-
import android.graphics.Bitmap;
-
import android.graphics.Canvas;
-
import android.graphics.Color;
-
import android.graphics.Matrix;
-
import android.graphics.Paint;
-
import android.graphics.Path;
-
import android.graphics.RectF;
-
import android.util.AttributeSet;
-
import android.util.DisplayMetrics;
-
import android.view.MotionEvent;
-
import android.view.View;
-
-
import com.example.hand.R;
-
import com.example.hand.utils.Bezier;
-
import com.example.hand.utils.ControlTimedPoints;
-
import com.example.hand.utils.TimedPoint;
-
-
public class SignatureView extends View {
-
// View state
-
private List<TimedPoint> 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<TimedPoint>();
-
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));
-
-
TimedPoint startPoint = curve.startPoint;
-
TimedPoint endPoint = curve.endPoint;
-
-
float velocity = endPoint.velocityFrom(startPoint);
-
velocity = Float.isNaN(velocity) ? 0.0f : velocity;
-
-
velocity = mVelocityFilterWeight * velocity + (1 - mVelocityFilterWeight) * mLastVelocity;
-
-
// The new width is a function of the velocity. Higher velocities
-
// correspond to thinner strokes.
-
float newWidth = strokeWidth(velocity);
-
-
// The Bezier's width starts out as last curve's final width, and
-
// gradually changes to the stroke width just calculated. The new
-
// width calculation is based on the velocity between the Bezier's
-
// start and end mPoints.
-
addBezier(curve, mLastWidth, newWidth);
-
-
mLastVelocity = velocity;
-
mLastWidth = newWidth;
-
-
// Remove the first element from the list,
-
// so that we always have no more than 4 mPoints in mPoints array.
-
mPoints.remove(0);
-
}
-
}
-
-
private void addBezier(Bezier curve, float startWidth, float endWidth) {
-
ensureSignatureBitmap();
-
float originalWidth = mPaint.getStrokeWidth();
-
float widthDelta = endWidth - startWidth;
-
float drawSteps = (float) Math.floor(curve.length());
-
-
for (int i = 0; i < drawSteps; i++) {
-
// Calculate the Bezier (x, y) coordinate for this step.
-
float t = ((float) i) / drawSteps;
-
float tt = t * t;
-
float ttt = tt * t;
-
float u = 1 - t;
-
float uu = u * u;
-
float uuu = uu * u;
-
-
float x = uuu * curve.startPoint.x;
-
x += 3 * uu * t * curve.control1.x;
-
x += 3 * u * tt * curve.control2.x;
-
x += ttt * curve.endPoint.x;
-
-
float y = uuu * curve.startPoint.y;
-
y += 3 * uu * t * curve.control1.y;
-
y += 3 * u * tt * curve.control2.y;
-
y += ttt * curve.endPoint.y;
-
-
// Set the incremental stroke width and draw.
-
mPaint.setStrokeWidth(startWidth + ttt * widthDelta);
-
mSignatureBitmapCanvas.drawPoint(x, y, mPaint);
-
expandDirtyRect(x, y);
-
}
-
-
mPaint.setStrokeWidth(originalWidth);
-
}
-
-
private ControlTimedPoints calculateCurveControlPoints(TimedPoint s1, TimedPoint s2, TimedPoint s3) {
-
float dx1 = s1.x - s2.x;
-
float dy1 = s1.y - s2.y;
-
float dx2 = s2.x - s3.x;
-
float dy2 = s2.y - s3.y;
-
-
TimedPoint m1 = new TimedPoint((s1.x + s2.x) / 2.0f, (s1.y + s2.y) / 2.0f);
-
TimedPoint m2 = new TimedPoint((s2.x + s3.x) / 2.0f, (s2.y + s3.y) / 2.0f);
-
-
float l1 = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1);
-
float l2 = (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
-
-
float dxm = (m1.x - m2.x);
-
float dym = (m1.y - m2.y);
-
float k = l2 / (l1 + l2);
-
TimedPoint cm = new TimedPoint(m2.x + dxm * k, m2.y + dym * k);
-
-
float tx = s2.x - cm.x;
-
float ty = s2.y - cm.y;
-
-
return new ControlTimedPoints(new TimedPoint(m1.x + tx, m1.y + ty), new TimedPoint(m2.x + tx, m2.y + ty));
-
}
-
-
private float strokeWidth(float velocity) {
-
return Math.max(mMaxWidth / (velocity + 1), mMinWidth);
-
}
-
-
/**
-
* Called when replaying history to ensure the dirty region includes all
-
* mPoints.
-
*
-
* @param historicalX
-
* the previous x coordinate.
-
* @param historicalY
-
* the previous y coordinate.
-
*/
-
private void expandDirtyRect(float historicalX, float historicalY) {
-
if (historicalX < mDirtyRect.left) {
-
mDirtyRect.left = historicalX;
-
} else if (historicalX > mDirtyRect.right) {
-
mDirtyRect.right = historicalX;
-
}
-
if (historicalY < mDirtyRect.top) {
-
mDirtyRect.top = historicalY;
-
} else if (historicalY > mDirtyRect.bottom) {
-
mDirtyRect.bottom = historicalY;
-
}
-
}
-
-
/**
-
* Resets the dirty region when the motion event occurs.
-
*
-
* @param eventX
-
* the event x coordinate.
-
* @param eventY
-
* the event y coordinate.
-
*/
-
private void resetDirtyRect(float eventX, float eventY) {
-
-
// The mLastTouchX and mLastTouchY were set when the ACTION_DOWN motion
-
// event occurred.
-
mDirtyRect.left = Math.min(mLastTouchX, eventX);
-
mDirtyRect.right = Math.max(mLastTouchX, eventX);
-
mDirtyRect.top = Math.min(mLastTouchY, eventY);
-
mDirtyRect.bottom = Math.max(mLastTouchY, eventY);
-
}
-
-
private void setIsEmpty(boolean newValue) {
-
mIsEmpty = newValue;
-
if (mOnSignedListener != null) {
-
if (mIsEmpty) {
-
mOnSignedListener.onClear();
-
} else {
-
mOnSignedListener.onSigned();
-
}
-
}
-
}
-
-
private void ensureSignatureBitmap() {
-
if (mSignatureBitmap == null) {
-
mSignatureBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
-
mSignatureBitmapCanvas = new Canvas(mSignatureBitmap);
-
}
-
}
-
-
private int convertDpToPx(float dp) {
-
return Math.round(dp * (getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
-
}
-
-
public interface OnSignedListener {
-
public void onSigned();
-
-
public void onClear();
-
}
-
}
最后我集成到项目里面的效果图 如上图
如果大家有其他问题 欢迎加入我的qq群讨论 开发一群:454430053开发二群:537532956
文章来源: wukong.blog.csdn.net,作者:再见孙悟空_,版权归原作者所有,如需转载,请联系作者。
原文链接:wukong.blog.csdn.net/article/details/77993757
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)