Android 签名(手势)控件

项目里有时会有那些要签名啊,或者要手绘的要求,为此就会要求有这样的控件存在,这里介绍两个方法:

一、Android 自带的 GestureOverlayView,添加于API-4,主要是用于识别手势的。

对于签名也可以完成大部分工作,但是有个问题:多笔画的时候,两个笔画之间间隔太久会自动清空前面所有笔画。我还么有找解决方法。

使用很简单:

在你的xml文件里添加这个控件就可以(一个透明层):

<android.gesture.GestureOverlayView 
    android:id="@+id/gov"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    android:gestureColor="#ffffff"
    android:fadeEnabled="false"
    android:gestureStrokeType="multiple"
    android:gestureStrokeLengthThreshold="0.1"
    android:gestureStrokeSquarenessThreshold="0.1"
    android:gestureStrokeAngleThreshold="0.1">
</android.gesture.GestureOverlayView>

有几个属性简单解释一下:fadeEnable,是手势的淡出效果,在做签名的时候就不用了;gestureStrokeType,有两个值,single和multiple,单笔画和多笔画,签名用多笔画;

gestureStrokeLengthThreshold、gestureStrokeSquarenessThreshold、gestureStrokeAngleThreshold 分别是长度、方形、角度的最小识别值,简单说就是对手势的识别精细度。在签名的要求中可能不是很重要。

然后可以把这个签名(手势)保存成Bitmap:

public Bitmap saveSignature() {
	GestureOverlayView gestureOverlayView = (GestureOverlayView)findViewById(R.id.gov);
	gestureOverlayView.setDrawingCacheEnabled(true);
	return Bitmap.createBitmap(gestureOverlayView.getDrawingCache()); 
}


二、如果要求要可以多笔画间隔无限时,手动控制清空的情况,那么可以用自定义控件实现:

public class DrawBoard extends View {
	
	private static final float STROKE_WIDTH = 5f; // 笔画的宽度
	
	/*
	 * 笔画的一半宽度,用于在获取签名(手势)的矩形区域的时候将所有的笔画都框进去。
	 * 因为左上角和右下角的点是在笔画的那个点的中心的,所以左上角(x,y)->(x-w/2, y-w/2), 右下角(x,y)->(x+w/2, y+w/2)
	 */
	private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
	
	private Paint paint = new Paint();
	private Path path = new Path();
	
	private float lastTouchX;
	private float lastTouchY;
	private final RectF dirtyRect = new RectF(); // 用于框出签名(手势)的区域

	public DrawBoard(Context context, AttributeSet attrs) {
		super(context, attrs);
		paint.setAntiAlias(true); //反锯齿
		paint.setColor(Color.BLACK);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeJoin(Paint.Join.ROUND); // 连接处圆润
		paint.setStrokeWidth(STROKE_WIDTH);
	}

	public void clear() {
		path.reset();
		invalidate();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawPath(path, paint);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float eventX = event.getX();
		float eventY = event.getY();

		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				path.moveTo(eventX, eventY);
				lastTouchX = eventX;
				lastTouchY = eventY;
				return true;
	
			case MotionEvent.ACTION_MOVE:
			case MotionEvent.ACTION_UP:
				resetDirtyRect(eventX, eventY); // 和最后一个坐标值比较更新图形矩形左上角和右下角
				int historySize = event.getHistorySize();
				for (int i = 0; i < historySize; i++) {
					float historicalX = event.getHistoricalX(i);
					float historicalY = event.getHistoricalY(i);
					expandDirtyRect(historicalX, historicalY); // 和历史坐标值比较更新图形矩形左上角和右下角
					path.lineTo(historicalX, historicalY);
				}
				path.lineTo(eventX, eventY);
				break;
	
			default: return false;
			}

		invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
				(int) (dirtyRect.top - HALF_STROKE_WIDTH),
				(int) (dirtyRect.right + HALF_STROKE_WIDTH),
				(int) (dirtyRect.bottom + HALF_STROKE_WIDTH)); //刷新整个图型区域

		lastTouchX = eventX;
		lastTouchY = eventY;

		return true;
	}

	private void expandDirtyRect(float historicalX, float historicalY) {
		if (historicalX < dirtyRect.left) {
			dirtyRect.left = historicalX;
		} else if (historicalX > dirtyRect.right) {
			dirtyRect.right = historicalX;
		}

		if (historicalY < dirtyRect.top) {
			dirtyRect.top = historicalY;
		} else if (historicalY > dirtyRect.bottom) {
			dirtyRect.bottom = historicalY;
		}
	}

	private void resetDirtyRect(float eventX, float eventY) {
		dirtyRect.left = Math.min(lastTouchX, eventX);
		dirtyRect.right = Math.max(lastTouchX, eventX);
		dirtyRect.top = Math.min(lastTouchY, eventY);
		dirtyRect.bottom = Math.max(lastTouchY, eventY);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值