Android UI设计之自定义DrawView组件,实现数字签名效果

最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要实现原理就是利用了View的绘图原理,把用户在屏幕上的手指移动轨迹显示在屏幕上,接着把在屏幕上显示的轨迹View转换成一张图片,最后把图片保存到本地或者上传到服务器...

还是老规矩,首先看一下工程目录吧:


public class DrawView extends View {

	/**
	 * 签名画笔
	 */
	private Paint paint;
	/**
	 * 签名画布
	 */
	private Canvas cacheCanvas;
	/**
	 * 画笔路径
	 */
	private Path path;
	/**
	 * 缓存图片
	 */
	private Bitmap cacheBitmap;
	/**
	 * 图片宽度
	 */
	private int width;
	/**
	 * 图片高度
	 */
	private int height;
	/**
	 * 手指触摸屏幕时的X,Y坐标
	 */
	private float xDown, yDown;
	/**
	 * 是否正在绘制
	 */
	private boolean isDrawing = false;

	/**
	 * 默认画笔颜色
	 */
	private int paintColor = Color.CYAN;

	/**
	 * 默认画板背景色
	 */
	private int canvasColor = Color.parseColor("#bbccaa");

	public DrawView(Context context, int width, int height) {
		super(context);
		this.width = width;
		this.height = height;
		initWedgits();
	}

	/**
	 * 初始化组件
	 */
	private void initWedgits() {
		try {
			paint = new Paint(Paint.DITHER_FLAG);
			// 设置抗锯齿
			paint.setAntiAlias(true);
			// 设置画笔宽度
			paint.setStrokeWidth(3);
			paint.setDither(true);
			// 设置样式
			paint.setStyle(Paint.Style.STROKE);
			paint.setStrokeJoin(Paint.Join.ROUND);
			paint.setStrokeCap(Paint.Cap.ROUND);
			// 画笔颜色
			paint.setColor(paintColor);
			// 绘制路径
			path = new Path();
			// 创建空缓存图片
			cacheBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
			// 把画布内容画到空缓存图片上
			cacheCanvas = new Canvas(cacheBitmap);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		canvas.drawColor(canvasColor);
		canvas.drawBitmap(cacheBitmap, 0, 0, paint);
		canvas.drawPath(path, paint);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// 记录手指摁下屏幕时的X坐标
		final float x = event.getX();
		// 记录手指摁下屏幕时的Y坐标
		final float y = event.getY();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// 手指摁下时清空之前的设置
			path.reset();
			// 设置路径起始点
			path.moveTo(x, y);
			xDown = x;
			yDown = y;
			isDrawing = true;
			break;
		case MotionEvent.ACTION_MOVE:
			// 移动下一点
			path.quadTo(xDown, yDown, x, y);
			// 重新设置起点
			xDown = x;
			yDown = y;
			isDrawing = true;
			break;
		case MotionEvent.ACTION_UP:
			path.lineTo(xDown, yDown);
			// 手指抬起时绘制路径
			cacheCanvas.drawPath(path, paint);
			// 路径重置
			path.reset();
			isDrawing = false;
			break;
		default:
			break;
		}
		// 刷新界面
		invalidate();
		return true;
	}

	/**
	 * 设置画笔颜色
	 * 
	 * @param color
	 *            画笔颜色
	 */
	public void setPaintColor(int color) {
		paintColor = color;
	}

	/**
	 * 设置画板颜色
	 * 
	 * @param color
	 *            画板颜色
	 */
	public void setCanvasColor(int color) {
		canvasColor = color;
	}

	/**
	 * 返回绘画状态
	 * 
	 * @return【true:正在绘制】【false:绘制完成】
	 */
	public boolean getDrawState() {
		return isDrawing;
	}

	/**
	 * 返回Bitmap
	 * 
	 * @return 返回绘制的图片
	 */
	public Bitmap getBitmap() {
		return cacheBitmap;
	}
}

DrawView的代码注释都很清晰,我还是大致说下DrawView的执行逻辑吧,DrawView继承了View也就是说具有了View的所有功能,要实现图片绘制就要实现onDraw()方法,要实现对手指在屏幕上的轨迹绘制就需要获取轨迹坐标,所以需要重写onTouchEvent()放法,重点在onTouchEvent()方法中。当手指摁下时我们绘制起点,但是在绘制起点前需要先调用path.reset()方法,防止path进行二次重绘,path的moveTo方法就是来绘制当前触摸事件的起点,摁下完成之后调用inValidate()方法进行界面刷新。当手指移动时调用path.quadTo()方法,这个方法就是追加的意思,把新坐标点追加到path中,手指移动之后再调用inValidate()方法进行界面刷新,最后当手指抬起时,把在当前事件周期内的轨迹绘制到画板cacheCanvas上,最后再调用inValidate()方法进行界面刷新,因此一次的手指移动轨迹就绘制完成,当要进行下一次的绘制,就是重复以上操作了...


接下来我们看看DrawView的使用吧,首先看一下布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:background="#ffffff">

	<TextView
		android:id="@+id/title"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="请绘制签名"
		android:textSize="18sp"
		android:layout_margin="5dip"
		android:gravity="center"
		android:textColor="#000000" />

	<FrameLayout
		android:id="@+id/contents"
		android:layout_width="fill_parent"
		android:layout_height="0dip"
		android:layout_weight="1"
		android:layout_gravity="center"
		android:background="#aabbcc">
	</FrameLayout>

	<Button
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:onClick="save"
		android:text="保存签名" />
</LinearLayout>

乍一看布局文件中并没有使用我们自定义的DrawView,不过不用着急我是使用了通过在FrameLayout中动态添加的方法把DrawView添加进来的,好了,那紧接着看看MainActivity中的代码实现吧:

public class MainActivity extends Activity {

	private FrameLayout frameLayout;
	private DrawView drawView;
	private TextView title;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		initWedgits();
	}

	/**
	 * 初始化组件
	 */
	private void initWedgits() {
		try {
			frameLayout = (FrameLayout) findViewById(R.id.contents);
			title = (TextView) findViewById(R.id.title);
			title.setText(Html.fromHtml("<b>China中国<tt>中国</tt></b>China真伟大!"));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onWindowFocusChanged(boolean hasFocus) {
		drawView = new DrawView(MainActivity.this, frameLayout.getWidth(), frameLayout.getHeight());
		frameLayout.addView(drawView);
	}

	/**
	 * 保存图片
	 * 
	 * @param view
	 */
	public void save(View view) {
		try {
			File file = new File(Environment.getExternalStorageDirectory()
					.getAbsolutePath() + "/handle.png");
			if (file.exists()) {
				file.delete();
			}
			file.createNewFile();
			if (drawView.getBitmap().compress(CompressFormat.PNG, 100, new FileOutputStream(file))) {
				Toast.makeText(getApplicationContext(), "图片保存成功", 1000).show();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

在MainActivity中的代码没什么好解释的,相信你一看就懂,最主要的是在save方法中使用了Bitmap的compress()方法,就是把图片存储在文件中,当我们签名结束之后点击保存签名按钮,签名图片就保存在了本地文件中了,当然了如果你想上传到后台服务器也不难,就是使用个异步操作进行图片上传就行了...

扫描二维码关注公众号,回复: 9373086 查看本文章

说明:当你运行程序的时候,会看见China中国中国真伟大!的字样,其中China中国是加粗的效果,因为项目中有个需求让把汉字也加粗,上网上找了些方法,但是都是对英文和数字有效果对中文暂时没效果,我也是无意看源码中的注释,其中注释里边有加粗的文字说明,我就点击进去了,结果发现注释里的标签是<tt></tt>,当时脑子一转就想估计<tt>标签可以实现对汉字的加粗效果,呵呵,功夫不付有心人,把<tt>标签放到<b>里边已测试,果然有效果,呵呵,当时高兴坏了,现在再高兴一下,(*^__^*) 嘻嘻...

好了,现在我们运行程序来看一下效果图吧:

绘制签名:当点击了保存按钮后,进入图库看看吧:


好了,数字签名的讲解到这里了,欢迎观看


源码下载

发布了39 篇原创文章 · 获赞 87 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/llew2011/article/details/31403969