电子签名的作用:记录用户在设备上输入的信息,然后在本地保存图片。
首先在构造方法中初始化画笔和笔迹集合,画笔的属性主要有颜色、宽度、起始和结束的图形、拐角弧度和风格。笔迹集合方便客户多笔迹输入。
然后在onTouchEvent方法中使用Path类来记录用户接触设备并在设备上移动的痕迹,当用户接触设备就把当前的Path添加到笔迹集合中去,当用户移动的时候就刷新当前Path的路径。
最后使用onDraw方法将Canvas(画布)保存的笔迹绘制出来。
为了方便外界修改画笔的颜色和宽度,这里开放两个接口供外界调用,有两种方式:1、在代码中调用组件的set方法,可以在任意时候设置画笔属性;2、在xml文件中静态指定画笔的颜色和宽度,通过如下代码设置:
<resources> <declare-styleable name="SignView"> <attr name="lineColor" format="color"/> <attr name="lineWidth" format="dimension"/> </declare-styleable></resources>然后在SignView的构造方法中获取在xml中设置的属性
public SignView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SignView); parseTyepdArray(a); } init();// 普通初始化 initLinePpaint(); }PRivate void parseTyepdArray(TypedArray a) { lineColor = a.getColor(styleable.SignView_lineColor, Color.RED); lineWidth = a.getDimension(styleable.SignView_lineWidth, 25); a.recycle(); }这样我们就能在xml文件中使用自定义的属性了
<com.example.signviewdemo.SignView android:id="@+id/signView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="4" android:background="@android:color/white" app:lineColor="@android:color/holo_orange_dark" app:lineWidth="10dp" />这里需要在布局文件的根节点定义app属性,只需要添加xmlns:app="http://schemas.android.com/apk/res-auto"即可。<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.signviewdemo.MainActivity" android:orientation="vertical" android:background="@android:color/darker_gray" >接下来实现清空输入的笔迹/** * 清空输入 */ public void clearPath() { lines.removeAll(lines); invalidate(); }最后将整个View以图片的形式保存到本地/** * 将图片保存到文件 */ public boolean saveImageToFile(String filePath) { try { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } String localFile=file.getAbsolutePath()+"/"+System.currentTimeMillis()+".png"; File f=new File(localFile); FileOutputStream fos=new FileOutputStream(f); getImage().compress(CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); return true; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } } /** * 将View保存为Bitmap */ public Bitmap getImage() { Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.RGB_565); Canvas canvas = new Canvas(bitmap); // 绘制背景 Drawable bgDrawable = getBackground(); if (bgDrawable != null) { bgDrawable.draw(canvas); } else { canvas.drawColor(Color.WHITE); } // 绘制View视图内容 draw(canvas); return bitmap; }SingView的完整代码:public class SignView extends View { private Paint linePaint;// 画笔 private ArrayList<Path> lines;// 写字的笔迹,支持多笔画 private int lineCount;// 记录笔画数目 private final int DEFAULT_LINE_WIDTH = 10;// 默认笔画宽度 private int lineColor = Color.BLACK;// 默认字迹颜色(黑色) private float lineWidth = DEFAULT_LINE_WIDTH;// 笔画宽度 public SignView(Context context) { super(context); // TODO Auto-generated constructor stub init();// 普通初始化 initLinePpaint(); } public SignView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SignView); parseTyepdArray(a); } init();// 普通初始化 initLinePpaint(); } public SignView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SignView); parseTyepdArray(a); } init();// 普通初始化 initLinePpaint(); } private void parseTyepdArray(TypedArray a) { lineColor = a.getColor(styleable.SignView_lineColor, Color.RED); lineWidth = a.getDimension(styleable.SignView_lineWidth, 25); a.recycle(); } private void init() { lines = new ArrayList<Path>(); } /** * 初始化画笔 */ private void initLinePpaint() { linePaint = new Paint(); linePaint.setColor(lineColor);// 画笔颜色 linePaint.setStrokeWidth(lineWidth);// 画笔宽度 linePaint.setStrokeCap(Cap.ROUND);// 设置笔迹的起始、结束为圆形 linePaint.setPathEffect(new CornerPathEffect(50));// PahtEfect指笔迹的风格,CornerPathEffect在拐角处添加弧度,弧度半径50像素点 linePaint.setStyle(Style.STROKE);// 设置画笔风格 } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub /** * 考虑到这个view会出现在lib工程里,因此使用if else */ if (event.getAction() == MotionEvent.ACTION_DOWN) { Path path = new Path(); path.moveTo(event.getX(), event.getY()); lines.add(path); lineCount = lines.size(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { lines.get(lineCount - 1).lineTo(event.getX(), event.getY()); invalidate(); } else { } return true; } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); if (lines != null && lines.size() > 0) { for (Path path : lines) { canvas.drawPath(path, linePaint); } } } // 开放设置画笔颜色和宽度的接口 /** * 开放设置画笔颜色的接口 * * @param lineColor */ public void setLineColor(int lineColor) { this.lineColor = lineColor; linePaint.setColor(lineColor); } /** * 开放设置画笔宽度的接口 * * @param lineWidth */ public void setLineWidth(float lineWidth) { this.lineWidth = lineWidth; linePaint.setStrokeWidth(lineWidth); } /** * 清空输入 */ public void clearPath() { lines.removeAll(lines); invalidate(); } /** * 将图片保存到文件 */ public boolean saveImageToFile(String filePath) { try { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } String localFile=file.getAbsolutePath()+"/"+System.currentTimeMillis()+".png"; File f=new File(localFile); FileOutputStream fos=new FileOutputStream(f); getImage().compress(CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); return true; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } } /** * 将View保存为Bitmap */ public Bitmap getImage() { Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.RGB_565); Canvas canvas = new Canvas(bitmap); // 绘制背景 Drawable bgDrawable = getBackground(); if (bgDrawable != null) { bgDrawable.draw(canvas); } else { canvas.drawColor(Color.WHITE); } // 绘制View视图内容 draw(canvas); return bitmap; }}MainActivity
public class MainActivity extends Activity implements OnClickListener{ private SignView signView; private Button btn_clear; private Button btn_save; private static final String SAVE_PATH=Environment.getExternalStorageDirectory()+"/SignViewDemo/"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); signView=(SignView) findViewById(R.id.signView); btn_clear=(Button) findViewById(R.id.btn_clear); btn_save=(Button) findViewById(R.id.btn_save); btn_clear.setOnClickListener(this); btn_save.setOnClickListener(this);// signView.setLineColor(Color.BLUE);// signView.setLineWidth(20); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()){ case R.id.btn_clear: signView.clearPath(); break; case R.id.btn_save: if(signView.saveImageToFile(SAVE_PATH)){ Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(MainActivity.this, "保存失败", Toast.LENGTH_SHORT).show(); } break; } }}==============2017年2月7日更新=============
添加翻转设备,不会清除内容的功能
//实现设备翻转,数据不会被清除 private static final String INSTANCE_STATE = "saved_instance"; private static final String LINE_COLOR = "line_color"; private static final String LINE_WIDTH = "line_width"; private static final String LINES = "lines"; @Override protected Parcelable onSaveInstanceState() { // TODO Auto-generated method stub final Bundle bundle = new Bundle(); Parcelable superState=super.onSaveInstanceState(); bundle.putParcelable(INSTANCE_STATE, superState); bundle.putInt(LINE_COLOR, getLineColor()); bundle.putFloat(LINE_WIDTH, getLineWidth()); bundle.putSerializable(LINES, lines); return bundle; } @SuppressWarnings("unchecked") @Override protected void onRestoreInstanceState(Parcelable state) { // TODO Auto-generated method stub if (state instanceof Bundle) { final Bundle bundle = (Bundle) state; lineColor = bundle.getInt(LINE_COLOR); lineWidth = bundle.getFloat(LINE_WIDTH); lines=(ArrayList<Path>) bundle.getSerializable(LINES); } try { super.onRestoreInstanceState(state); } catch (Exception e) { // TODO: handle exception state = null; } }项目名称:SignViewDemo
新闻热点
疑难解答