Android UI設(shè)計系列之自定義DrawView組件實現(xiàn)數(shù)字簽名效果(5)
最近項目中有個新的需求,用戶在完交易需要進(jìn)行輸入支付密碼付款的時候,要讓用戶簽下自己的簽名,提起到數(shù)字簽名這個東西,感覺有點高大上,后來想想數(shù)字簽名的原理也不是太復(fù)雜,主要實現(xiàn)原理就是利用了View的繪圖原理,把用戶在屏幕上的手指移動軌跡顯示在屏幕上,接著把在屏幕上顯示的軌跡View轉(zhuǎn)換成一張圖片,最后把圖片保存到本地或者上傳到服務(wù)器...
還是老規(guī)矩,首先看一下工程目錄吧:

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坐標(biāo)
*/
private float xDown, yDown;
/**
* 是否正在繪制
*/
private boolean isDrawing = false;
/**
* 默認(rèn)畫筆顏色
*/
private int paintColor = Color.CYAN;
/**
* 默認(rèn)畫板背景色
*/
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);
// 設(shè)置抗鋸齒
paint.setAntiAlias(true);
// 設(shè)置畫筆寬度
paint.setStrokeWidth(3);
paint.setDither(true);
// 設(shè)置樣式
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
// 畫筆顏色
paint.setColor(paintColor);
// 繪制路徑
path = new Path();
// 創(chuàng)建空緩存圖片
cacheBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
// 把畫布內(nèi)容畫到空緩存圖片上
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坐標(biāo)
final float x = event.getX();
// 記錄手指摁下屏幕時的Y坐標(biāo)
final float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指摁下時清空之前的設(shè)置
path.reset();
// 設(shè)置路徑起始點
path.moveTo(x, y);
xDown = x;
yDown = y;
isDrawing = true;
break;
case MotionEvent.ACTION_MOVE:
// 移動下一點
path.quadTo(xDown, yDown, x, y);
// 重新設(shè)置起點
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;
}
/**
* 設(shè)置畫筆顏色
*
* @param color
* 畫筆顏色
*/
public void setPaintColor(int color) {
paintColor = color;
}
/**
* 設(shè)置畫板顏色
*
* @param color
* 畫板顏色
*/
public void setCanvasColor(int color) {
canvasColor = color;
}
/**
* 返回繪畫狀態(tài)
*
* @return【true:正在繪制】【false:繪制完成】
*/
public boolean getDrawState() {
return isDrawing;
}
/**
* 返回Bitmap
*
* @return 返回繪制的圖片
*/
public Bitmap getBitmap() {
return cacheBitmap;
}
}
DrawView的代碼注釋都很清晰,我還是大致說下DrawView的執(zhí)行邏輯吧,DrawView繼承了View也就是說具有了View的所有功能,要實現(xiàn)圖片繪制就要實現(xiàn)onDraw()方法,要實現(xiàn)對手指在屏幕上的軌跡繪制就需要獲取軌跡坐標(biāo),所以需要重寫onTouchEvent()放法,重點在onTouchEvent()方法中。當(dāng)手指摁下時我們繪制起點,但是在繪制起點前需要先調(diào)用path.reset()方法,防止path進(jìn)行二次重繪,path的moveTo方法就是來繪制當(dāng)前觸摸事件的起點,摁下完成之后調(diào)用inValidate()方法進(jìn)行界面刷新。當(dāng)手指移動時調(diào)用path.quadTo()方法,這個方法就是追加的意思,把新坐標(biāo)點追加到path中,手指移動之后再調(diào)用inValidate()方法進(jìn)行界面刷新,最后當(dāng)手指抬起時,把在當(dāng)前事件周期內(nèi)的軌跡繪制到畫板cacheCanvas上,最后再調(diào)用inValidate()方法進(jìn)行界面刷新,因此一次的手指移動軌跡就繪制完成,當(dāng)要進(jìn)行下一次的繪制,就是重復(fù)以上操作了...
接下來我們看看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中動態(tài)添加的方法把DrawView添加進(jìn)來的,好了,那緊接著看看MainActivity中的代碼實現(xiàn)吧:
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真?zhèn)ゴ螅?));
} 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()方法,就是把圖片存儲在文件中,當(dāng)我們簽名結(jié)束之后點擊保存簽名按鈕,簽名圖片就保存在了本地文件中了,當(dāng)然了如果你想上傳到后臺服務(wù)器也不難,就是使用個異步操作進(jìn)行圖片上傳就行了...
說明:當(dāng)你運(yùn)行程序的時候,會看見China中國中國真?zhèn)ゴ?!的字樣,其?strong>China和中國是加粗的效果,因為項目中有個需求讓把漢字也加粗,上網(wǎng)上找了些方法,但是都是對英文和數(shù)字有效果對中文暫時沒效果,我也是無意看源碼中的注釋,其中注釋里邊有加粗的文字說明,我就點擊進(jìn)去了,結(jié)果發(fā)現(xiàn)注釋里的標(biāo)簽是<tt></tt>,當(dāng)時腦子一轉(zhuǎn)就想估計<tt>標(biāo)簽可以實現(xiàn)對漢字的加粗效果,呵呵,功夫不付有心人,把<tt>標(biāo)簽放到<b>里邊已測試,果然有效果,呵呵,當(dāng)時高興壞了,現(xiàn)在再高興一下,(*^__^*) 嘻嘻...
好了,現(xiàn)在我們運(yùn)行程序來看一下效果圖吧:
繪制簽名:

當(dāng)點擊了保存按鈕后,進(jìn)入圖庫看看吧:

好了,數(shù)字簽名的講解到這里了,謝謝大家的閱讀。
源碼下載: Android UI實現(xiàn)數(shù)字簽名效果
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android ViewPager無限循環(huán)滑動并可自動滾動完整實例
對于Android ViewPager廣告頁可無限循環(huán)滑動并可自動滾動帶有小圓點的這個功能很多APP都有這個功能,這里為大家提供了完整的實例代碼2018-03-03
Android中AlertDialog四種對話框的最科學(xué)編寫用法(實例代碼)
這篇文章主要介紹了Android中AlertDialog四種對話框的最科學(xué)編寫用法,本文通過代碼講解的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-11-11
微信瀏覽器彈出框滑動時頁面跟著滑動的實現(xiàn)代碼(兼容Android和IOS端)
小編在做微信開發(fā)的時候遇到微信瀏覽器彈出框滑動時頁面跟著滑動的效果,下面把關(guān)鍵代碼分享給大家,需要的朋友參考下2016-11-11
Android四大組件之Service(服務(wù))實例詳解
這篇文章主要介紹了Android四大組件之Service(服務(wù))的用法,結(jié)合實例形式詳細(xì)分析了Service的基本概念,類型,用法與相關(guān)注意事項,需要的朋友可以參考下2016-01-01
Android開發(fā)實現(xiàn)TextView顯示豐富的文本
這篇文章主要介紹了Android開發(fā)實現(xiàn)TextView顯示豐富的文本,涉及Android中TextView的使用技巧,需要的朋友可以參考下2015-12-12
Android自定義LinearLayout布局顯示不完整的解決方法
這篇文章主要給大家介紹了關(guān)于Android自定義LinearLayout但布局顯示不完整的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11

