Android 提供了很多丰富、实用而且很有特色的功能。比如,语音识别、手写签名等等。本篇就为你介绍如何在android上进行个性化的手写签名。



首先大致说说需求:这是一个追求时尚、张扬个性的时代,我们希望在签名的地方,签名的是自己手写出来的很有个性的艺术字,而非根据手势识别出来的标准字体。



设计思路如下,在画板上进行签名(其实就是绘制图片),完成后保存为图片。然后将图片按照一定的比率进行缩放并显示在指定的位置。



这里给出一个实例,实例只是一个简单的例子,如有需要可以进行必要的扩展。这里我们需要一个Listener、一个Dialog、一个Activity这个三个java类。两个layout XML文件。



Listener很简单,主要是对手写板对话框的一个监听。


public interface DialogListener {






public void refreshActivity(Object object);





}

接着是画板的Dialog


package cn.handwriting;





import android.app.Dialog;


import android.content.Context;


import android.graphics.Bitmap;


import android.graphics.Bitmap.Config;


import android.graphics.Canvas;


import android.graphics.Color;


import android.graphics.Paint;


import android.graphics.Path;


import android.os.Bundle;


import android.view.MotionEvent;


import android.view.View;


import android.view.Window;


import android.view.WindowManager.LayoutParams;


import android.widget.Button;


import android.widget.FrameLayout;








public class WritePadDialog extends Dialog {






Context context;



LayoutParams p ;



DialogListener dialogListener;






public WritePadDialog(Context context,DialogListener dialogListener) {



super
(context);



this
.context = context;



this
.dialogListener = dialogListener;



}






static final int BACKGROUND_COLOR = Color.WHITE;






static final int BRUSH_COLOR = Color.BLACK;






PaintView mView;






/** The index of the current color to use. */



int mColorIndex;






@Override



protected void onCreate(Bundle savedInstanceState) {



super
.onCreate(savedInstanceState);



requestWindowFeature(Window.FEATURE_NO_TITLE);



requestWindowFeature(Window.FEATURE_PROGRESS);



setContentView(R.layout.write_pad);






p = getWindow().getAttributes();
//获取对话框当前的参数值



p.height = 320;
//(int) (d.getHeight() * 0.4); //高度设置为屏幕的0.4



p.width = 480;
//(int) (d.getWidth() * 0.6); //宽度设置为屏幕的0.6



getWindow().setAttributes(p);
//设置生效









mView =
new
PaintView(context);



FrameLayout frameLayout = (FrameLayout) findViewById(R.id.tablet_view);



frameLayout.addView(mView);



mView.requestFocus();



Button btnClear = (Button) findViewById(R.id.tablet_clear);



btnClear.setOnClickListener(
new
View.OnClickListener() {






@Override



public void onClick(View v) {



mView.clear();



}



});






Button btnOk = (Button) findViewById(R.id.tablet_ok);



btnOk.setOnClickListener(
new
View.OnClickListener() {






@Override



public void onClick(View v) {



try
{



dialogListener.refreshActivity(mView.getCachebBitmap());



WritePadDialog.
this
.dismiss();



}
catch
(Exception e) {



e.printStackTrace();



}



}



});






Button btnCancel = (Button)findViewById(R.id.tablet_cancel);



btnCancel.setOnClickListener(
new
View.OnClickListener() {






@Override



public void onClick(View v) {



cancel();



}



});



}









/**



* This view implements the drawing canvas.



*



* It handles all of the input events and drawing functions.



*/



class PaintView extends View {



private Paint paint;



private Canvas cacheCanvas;



private Bitmap cachebBitmap;



private Path path;






public Bitmap getCachebBitmap() {



return
cachebBitmap;



}






public PaintView(Context context) {



super
(context);



init();



}






private void init(){



paint =
new
Paint();



paint.setAntiAlias(
true
);



paint.setStrokeWidth(3);



paint.setStyle(Paint.Style.STROKE);



paint.setColor(Color.BLACK);



path =
new
Path();



cachebBitmap = Bitmap.createBitmap(p.width, (int)(p.height*0.8), Config.ARGB_8888);



cacheCanvas =
new
Canvas(cachebBitmap);



cacheCanvas.drawColor(Color.WHITE);



}



public void clear() {



if
(cacheCanvas !=
null
) {






paint.setColor(BACKGROUND_COLOR);



cacheCanvas.drawPaint(paint);



paint.setColor(Color.BLACK);



cacheCanvas.drawColor(Color.WHITE);



invalidate();



}



}












@Override



protected void onDraw(Canvas canvas) {



// canvas.drawColor(BRUSH_COLOR);



canvas.drawBitmap(cachebBitmap, 0, 0,
null
);



canvas.drawPath(path, paint);



}






@Override



protected void onSizeChanged(int w, int h, int oldw, int oldh) {






int curW = cachebBitmap !=
null
? cachebBitmap.getWidth() : 0;



int curH = cachebBitmap !=
null
? cachebBitmap.getHeight() : 0;



if
(curW >= w && curH >= h) {



return
;



}






if
(curW < w)



curW = w;



if
(curH < h)



curH = h;






Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.ARGB_8888);



Canvas newCanvas =
new
Canvas();



newCanvas.setBitmap(newBitmap);



if
(cachebBitmap !=
null
) {



newCanvas.drawBitmap(cachebBitmap, 0, 0,
null
);



}



cachebBitmap = newBitmap;



cacheCanvas = newCanvas;



}






private float cur_x, cur_y;






@Override



public boolean onTouchEvent(MotionEvent event) {






float x = event.getX();



float y = event.getY();






switch
(event.getAction()) {



case
MotionEvent.ACTION_DOWN: {



cur_x = x;



cur_y = y;



path.moveTo(cur_x, cur_y);



break
;



}






case
MotionEvent.ACTION_MOVE: {



path.quadTo(cur_x, cur_y, x, y);



cur_x = x;



cur_y = y;



break
;



}






case
MotionEvent.ACTION_UP: {



cacheCanvas.drawPath(path, paint);



path.reset();



break
;



}



}






invalidate();






return
true
;



}



}





}

Activity是程序的入口,这个必不可少。


1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23


24


25


26


27


28


29


30


31


32


33


34


35


36


37


38


39


40


41


42


43


44


45


46


47


48


49


50


51


52


53


54


55


56


57


58


59


60


61


62


63


64


65


66


67


68


69


70


71


72


73


74


75


76


77


78


79


80


81


82


83


84


85


86


87


88


89


package cn.handwriting;





import java.io.ByteArrayOutputStream;


import java.io.File;


import java.io.FileOutputStream;


import java.io.IOException;


import android.app.Activity;


import android.graphics.Bitmap;


import android.os.Bundle;


import android.os.Environment;


import android.view.View;


import android.view.View.OnClickListener;


import android.widget.ImageView;


import android.widget.TextView;





public class HandwritingActivity extends Activity {



/** Called when the activity is first created. */






private Bitmap mSignBitmap;



private String signPath;



private ImageView ivSign;



private TextView tvSign;



@Override



public void onCreate(Bundle savedInstanceState) {



super
.onCreate(savedInstanceState);



setContentView(R.layout.main);



setTitle(
"欢迎使用手写签名"
);



ivSign =(ImageView)findViewById(R.id.iv_sign);



tvSign = (TextView)findViewById(R.id.tv_sign);






ivSign.setOnClickListener(signListener);



tvSign.setOnClickListener(signListener);



}









private OnClickListener signListener =
new
View.OnClickListener() {






@Override



public void onClick(View v) {



WritePadDialog writeTabletDialog =
new
WritePadDialog(



HandwritingActivity.
this
,
new
DialogListener() {



@Override



public void refreshActivity(Object object) {






mSignBitmap = (Bitmap) object;



signPath = createFile();



/*BitmapFactory.Options options = new BitmapFactory.Options();



options.inSampleSize = 15;



options.inTempStorage = new byte[5 * 1024];



Bitmap zoombm = BitmapFactory.decodeFile(signPath, options);*/



ivSign.setImageBitmap(mSignBitmap);



tvSign.setVisibility(View.GONE);



}



});



writeTabletDialog.show();



}



};






/**



* 创建手写签名文件



*



* @return



*/



private String createFile() {



ByteArrayOutputStream baos =
null
;



String _path =
null
;



try
{



String sign_dir = Environment.getExternalStorageDirectory() + File.separator;



_path = sign_dir + System.currentTimeMillis() +
".jpg"
;



baos =
new
ByteArrayOutputStream();



mSignBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);



byte[] photoBytes = baos.toByteArray();



if
(photoBytes !=
null
) {



new
FileOutputStream(
new
File(_path)).write(photoBytes);



}






}
catch
(IOException e) {



e.printStackTrace();



} finally {



try
{



if
(baos !=
null
)



baos.close();



}
catch
(IOException e) {



e.printStackTrace();



}



}



return
_path;



}


}

对应的两个layout文件

main.xml


1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23


24


<?xml version=
"1.0"
encoding=
"utf-8"
?>


<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"



android:layout_width=
"fill_parent"



android:layout_height=
"fill_parent"



android:orientation=
"vertical"
>






<ImageView



android:id=
"@+id/iv_sign"



android:layout_marginTop=
"50dp"



android:layout_width=
"wrap_content"



android:layout_height=
"wrap_content"



android:layout_gravity=
"center"



/>






<TextView



android:id=
"@+id/tv_sign"



android:layout_marginTop=
"50dp"



android:layout_below=
"@id/iv_sign"



android:layout_width=
"wrap_content"



android:layout_height=
"wrap_content"



android:layout_gravity=
"center"



android:text=
"点此签名"



/>


</LinearLayout>

write_pad.xml


1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23


24


25


26


27


28


29


30


31


32


33


34


35


36


37


38


39


40


41


42


43


<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"



xmlns:greendroid=
"http://schemas.android.com/apk/res/com.cyrilmottier.android.gdcatalog"



android:layout_width=
"fill_parent"



android:layout_height=
"fill_parent"



android:orientation=
"vertical"
>






<FrameLayout



android:id=
"@+id/tablet_view"



android:layout_width=
"fill_parent"



android:layout_height=
"0dp"



android:layout_weight=
"1"



android:background=
"@color/white"
>



</FrameLayout>






<LinearLayout



android:layout_width=
"fill_parent"



android:layout_height=
"wrap_content"



android:background=
"@android:drawable/bottom_bar"



android:paddingTop=
"4dp"
>






<Button



android:id=
"@+id/tablet_ok"



android:layout_width=
"0dp"



android:layout_height=
"wrap_content"



android:layout_weight=
"1"



android:text=
"确定"
/>






<Button



android:id=
"@+id/tablet_clear"



android:layout_width=
"0dp"



android:layout_height=
"wrap_content"



android:layout_weight=
"1"



android:text=
"清除"
/>






<Button



android:id=
"@+id/tablet_cancel"



android:layout_width=
"0dp"



android:layout_height=
"wrap_content"



android:layout_weight=
"1"



android:text=
"取消"
/>



</LinearLayout>





</LinearLayo