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()方法,就是把圖片存儲在文件中,當我們簽名結束之後點擊保存簽名按鈕,簽名圖片就保存在了本地文件中了,當然瞭如果你想上傳到後臺服務器也不難,就是使用個異步操作進行圖片上傳就行了...

說明:當你運行程序的時候,會看見China中國中國真偉大!的字樣,其中China中國是加粗的效果,因爲項目中有個需求讓把漢字也加粗,上網上找了些方法,但是都是對英文和數字有效果對中文暫時沒效果,我也是無意看源碼中的註釋,其中註釋裏邊有加粗的文字說明,我就點擊進去了,結果發現註釋裏的標籤是<tt></tt>,當時腦子一轉就想估計<tt>標籤可以實現對漢字的加粗效果,呵呵,功夫不付有心人,把<tt>標籤放到<b>裏邊已測試,果然有效果,呵呵,當時高興壞了,現在再高興一下,(*^__^*) 嘻嘻...

好了,現在我們運行程序來看一下效果圖吧:

繪製簽名:當點擊了保存按鈕後,進入圖庫看看吧:


好了,數字簽名的講解到這裏了,歡迎觀看


源碼下載

發佈了37 篇原創文章 · 獲贊 87 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章